Dependencies

# data wrangling
library(tidyverse)

# spatial data wrangling
library(sf)

# data visualisation
library(viridis) 

# format data visualisations
library(ggthemes)
library(patchwork)
library(showtext)
library(scales)
library(classInt)
library(ggtext)

# create maps
library(leaflet)
library(tmap)
library(mapdeck)
library(patchwork)
library(cowplot)

Setting theme

Set font style

# clean workspace
rm(list=ls())
# load font
font_add_google("Roboto Condensed", "robotocondensed")
# automatically use showtext to render text
showtext_auto()

Theme for maps

theme_map <- function(...) {
  theme_tufte() +
  theme(
    text = element_text(family = "robotocondensed", size = 20),
    # remove all axes
    axis.text.x = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks = element_blank()
    )
}

Theme for plots

theme_tufte2 <- function(...) {
  theme_tufte() +
  theme(
    text = element_text(family = "robotocondensed", size = 20),
    )
}

Argentina

Data

mobility data

## need to read this in 4 separate times - 202

# 2020 out
df20_b <- readRDS("/Volumes/RECAST/data/outputs/argentina/movements/2020_04_mov.rds") %>% 
  mutate(GEOMETRY = NULL) %>% 
  dplyr::filter(country == "AR") %>% 
  st_as_sf(coords = c("end_lon", "end_lat"), 
                                      crs = 'EPSG:4326')

# 2022 out
df22_b <- readRDS("/Volumes/RECAST/data/outputs/argentina/movements/2022_03_mov.rds") %>% 
  mutate(GEOMETRY = NULL) %>% 
  dplyr::filter(country == "AR") %>% 
  st_as_sf(coords = c("end_lon", "end_lat"), 
                                      crs = 'EPSG:4326')

boundary data

adm_shp <- st_read("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_ARG_shp/gadm41_ARG_2.shp") %>% 
  st_simplify(preserveTopology = T,
              dTolerance = 1000) %>% 
  st_make_valid() %>% 
  st_transform(crs = 'EPSG:4326')
Reading layer `gadm41_ARG_2' from data source 
  `/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_ARG_shp/gadm41_ARG_2.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 502 features and 13 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -73.56056 ymin: -55.06153 xmax: -53.59184 ymax: -21.78137
Geodetic CRS:  WGS 84
adm1_shp <- st_read("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_ARG_shp/gadm41_ARG_1.shp") %>% 
  st_simplify(preserveTopology = T,
              dTolerance = 1000) %>% 
  st_make_valid() %>% 
  st_transform(crs = 'EPSG:4326')
Reading layer `gadm41_ARG_1' from data source 
  `/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_ARG_shp/gadm41_ARG_1.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 24 features and 11 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -73.56056 ymin: -55.06153 xmax: -53.59184 ymax: -21.78137
Geodetic CRS:  WGS 84
region_shp <- st_read("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_ARG_shp/gadm41_ARG_0.shp")%>% 
  st_simplify(preserveTopology = T,
              dTolerance = 1000) %>% 
  st_make_valid() %>% 
  st_transform(crs = 'EPSG:4326')
Reading layer `gadm41_ARG_0' from data source 
  `/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_ARG_shp/gadm41_ARG_0.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 2 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -73.56056 ymin: -55.06153 xmax: -53.59184 ymax: -21.78137
Geodetic CRS:  WGS 84

Data wrangling

area_names <- c("José C. Paz", "San Miguel", "Morón", "Capital Federal", "Esteban Echeverría", "Florencio Varela")

# filter for the area names which are within Buenos Aires
df20_out <- df20_b %>% dplyr::filter(start_polygon_name %in% area_names)
df22_out <- df22_b %>% dplyr::filter(start_polygon_name %in% area_names)

df20_out$start_polygon_name <- 'Buenos Aires'
df22_out$start_polygon_name <- 'Buenos Aires'

df20_out <- df20_out %>% filter(!end_polygon_name %in% area_names)
df22_out <- df22_out %>% filter(!end_polygon_name %in% area_names)

Define distance

df20_out <- df20_out %>% mutate(
  distance_class = case_when(length_km < 100 ~ "<100",
                             length_km >= 100 ~ ">100"))

df22_out <- df22_out %>% mutate(
  distance_class = case_when(length_km < 100 ~ "<100",
                             length_km >= 100 ~ ">100"))

preserve a unique geometry

df20_out <- df20_out %>%
  group_by(end_polygon_name) %>%
  mutate(geometry = st_union(geometry)) %>%
  ungroup()

df22_out <- df22_out %>%
  group_by(end_polygon_name) %>%
  mutate(geometry = st_union(geometry)) %>%
  ungroup()

Sum of flows

outflows_df_20 <- df20_out %>% 
  filter(start_polygon_name != end_polygon_name) %>% 
  group_by(start_polygon_name, end_polygon_name, geometry, distance_class) %>% 
  dplyr::summarise(
    sum_outflow = sum(n_crisis, na.rm = T)) %>% 
  ungroup() 
`summarise()` has grouped output by 'start_polygon_name', 'end_polygon_name', 'geometry'. You can override using the `.groups` argument.
outflows_df_22 <- df22_out %>% 
  filter(start_polygon_name != end_polygon_name) %>% 
  group_by(start_polygon_name, end_polygon_name, geometry, distance_class) %>% 
  dplyr::summarise(
    sum_outflow = sum(n_crisis, na.rm = T)) %>% 
  ungroup() 
`summarise()` has grouped output by 'start_polygon_name', 'end_polygon_name', 'geometry'. You can override using the `.groups` argument.

Check alignment between data frames

p <- ggplot() + 
  geom_sf(data = adm_shp,
          color = "gray60", 
          size = 0.1) 

last_plot()

p <- p +
  geom_point(data = outflows_df_20,
    aes(geometry = geometry),
    stat = "sf_coordinates"
  ) 
last_plot()

Add year

outflows_df_20$year <- '2020'
outflows_df_22$year <- '2022'

Bind outflows

outflows_df <- rbind(outflows_df_20, outflows_df_22)

Join flows to polygons

mob_indicators_1 <- st_join(adm_shp, outflows_df)

classify data into quantiles

mob_indicators_1$new_jenk_class <- classify_intervals(mob_indicators_1$sum_outflow, n = 5, style = "quantile", factor = TRUE)
Warning: var has missing values, omitted in finding classes
outflow_labels_1 <- levels(mob_indicators_1$new_jenk_class)
outflow_labels_1 <- gsub("^.|.$", "",  outflow_labels_1)
outflow_labels_1 <- gsub("\\.[0-9]+", "",  outflow_labels_1)
outflow_labels_1 <- gsub("\\,", "-",  outflow_labels_1)
levels(mob_indicators_1$new_jenk_class) <- outflow_labels_1

# mob_indicators_1 <- mob_indicators_1 %>% 
  # mutate(new_jenk_class = str_replace(new_jenk_class, ",", "-"))

# change geometry
shp_reg <- region_shp %>% st_transform(crs = 'EPSG:4326')
mob_indicators_1$new_jenk_class <- mob_indicators_1$new_jenk_class %>% replace_na("10-32")
mob_indicators_1 <- na.omit(mob_indicators_1)

Plotting

Creating individual country map


shp_reg$centroid <- shp_reg %>% 
  st_centroid() %>% 
  st_geometry()
Warning: st_centroid assumes attributes are constant over geometries
padding_width <- 17 
padding_height <- 22

ggplot(data = mob_indicators_1, 
                           aes(fill = new_jenk_class )) +
  geom_sf(col = "white", size = .2) + 
  coord_sf() +
  scale_fill_brewer(palette = "OrRd", 
                    direction = 1, 
                    labels = c("10-32", "32-242", "243-1,640", "1641-30,291", "> 30,292"), 
                    na.value="black") +
  facet_grid(distance_class ~ year) +
  labs(title = "A. Argentina",
       fill = "Number of out-moves") +
  theme_map() +
  guides(
    color='none',
    fill = guide_legend(
      keywidth = 4, 
      keyheight = 1,
      nrow = 1,
      title.position="top",
      label.position="bottom"
    )
  ) +
  theme(plot.title = element_text(size = 16, face = "bold"),
        plot.margin=margin(1,0,1,0,"cm"),
        legend.title = element_markdown(
          size=10, face = "bold", hjust=0.5, lineheight=0.45,
          color="black",
          margin=margin(0,0,-0.2,0,"cm")
          ),
        legend.text = element_text(size = 8),
        legend.position = "bottom",
        legend.spacing.x = unit(0, 'cm'),
        panel.background = element_rect(fill = "gray98", colour = "gray98")
        ) +
    geom_sf(data = shp_reg,
          col = "black", 
          size = 1,
          fill = "transparent") +
            coord_sf(xlim = c(shp_reg$centroid[[1]][1] - padding_width, 
                              shp_reg$centroid[[1]][1] + padding_width), 
           #          ylim = c(shp_reg$centroid[[1]][2] - padding_height, 
           #                   shp_reg$centroid[[1]][2] + padding_height), 
                    expand = FALSE)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

outflow_plot_arg <- last_plot()

Saving map

png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/argentina/cloropleth-arg.png", units="in", width=8, height=10, res=300)
  outflow_plot_arg
dev.off()
null device 
          1 

Create map for Buenos Aires

Short-distance

ba_deparment_shp <- adm1_shp %>% filter(NAME_1 == "Buenos Aires" |
                                          NAME_1 == "Ciudad de Buenos Aires" |
                                          NAME_1 == "Entre Ríos")

ba_deparment_shp$centroid <- ba_deparment_shp %>% 
  st_centroid() %>% 
  st_geometry()
Warning: st_centroid assumes attributes are constant over geometries
padding_width <- 3.5 
padding_height <- 3.2

# 2020
mob_indicators_1 %>% filter(NAME_1 == "Buenos Aires"| 
                              NAME_1 == "Ciudad de Buenos Aires" | 
                              NAME_1 == "Entre Ríos" |
                              NAME_1 == "Córdoba" |
                              NAME_1 == "Santa Fe") %>% 
  filter(year == "2020") %>% 
  filter(distance_class == "<100") %>% 
   ggplot(aes(fill = new_jenk_class)) +
     geom_sf(col = "white", size = .1) +
   coord_sf() +
  scale_fill_brewer(palette = "OrRd", 
                    direction = 1, 
                    labels = c("10-32", "32-242", "243-1,640", "1641-30,291", "> 30,292")) +
   theme_map() +
   theme(plot.title = element_text(size = 60),
         legend.position = "none",
         panel.background=element_rect(colour="black")
         ) +
   labs(title = "Buenos Aires") +
    geom_sf(data = ba_deparment_shp,
          col = "black", 
          size = 1,
          fill = "transparent") +
            coord_sf(xlim = c(ba_deparment_shp$centroid[[1]][1] - -.5, 
                              ba_deparment_shp$centroid[[1]][1] + padding_width), 
                     ylim = c(ba_deparment_shp$centroid[[1]][2] - -.5, 
                              ba_deparment_shp$centroid[[1]][2] + padding_height), 
                    expand = FALSE)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

ba_map2020 <- last_plot()

# 2022
mob_indicators_1 %>% filter(NAME_1 == "Buenos Aires"| 
                              NAME_1 == "Ciudad de Buenos Aires" | 
                              NAME_1 == "Entre Ríos" |
                              NAME_1 == "Córdoba" |
                              NAME_1 == "Santa Fe") %>% 
  filter(year == "2022") %>% 
  filter(distance_class == "<100") %>% 
   ggplot(aes(fill = new_jenk_class)) +
     geom_sf(col = "white", size = .1) +
   coord_sf() +
  scale_fill_brewer(palette = "OrRd", 
                    direction = 1, 
                    labels = c("10-32", "32-242", "243-1,640", "1641-30,291", "> 30,292")) +
   theme_map() +
   theme(plot.title = element_text(size = 60),
         legend.position = "none",
         panel.background=element_rect(colour="black")
         ) +
   labs(title = "Buenos Aires") +
    geom_sf(data = ba_deparment_shp,
          col = "black", 
          size = 1,
          fill = "transparent") +
            coord_sf(xlim = c(ba_deparment_shp$centroid[[1]][1] - -.5, 
                              ba_deparment_shp$centroid[[1]][1] + padding_width), 
                     ylim = c(ba_deparment_shp$centroid[[1]][2] - -.5, 
                              ba_deparment_shp$centroid[[1]][2] + padding_height), 
                    expand = FALSE)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

ba_map2022 <- last_plot()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/argentina/cloropleth-ba2020.png", units="in", width=8, height=10, res=300)
  ba_map2020
dev.off()
null device 
          1 
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/argentina/cloropleth-ba2022.png", units="in", width=8, height=10, res=300)
  ba_map2022
dev.off()
null device 
          1 

Create bar plot

Short-distance

col_pal <- c(#"#fef0d9",
             #"#fdcc8a",
             #"#fc8d59",
             "#e34a33",
             "#b30000")

# 2020
mob_indicators_1 %>% filter(year == "2020") %>%
  filter(distance_class == "<100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
    distinct(end_polygon_name, .keep_all=TRUE) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(end_polygon_name, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
       # axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_short2020 <- last_plot()

# 2022
mob_indicators_1 %>% filter(year == "2022") %>%
  filter(distance_class == "<100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  distinct(end_polygon_name, .keep_all=TRUE) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(end_polygon_name, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
        #axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_short2022 <- last_plot()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/argentina/barp_short2020.png", units="in", width=8, height=10, res=300)
  barp_short2020
dev.off()
null device 
          1 
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/argentina/barp_short2022.png", units="in", width=8, height=10, res=300)
  barp_short2022
dev.off()
null device 
          1 

Long-distance

2020

col_pal <- c("#fef0d9",
             "#fdcc8a"
             #"#fc8d59"
             #"#e34a33",
             #"#b30000"
  )

mob_indicators_1 %>% filter(year == "2020") %>%
  filter(distance_class == ">100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(NAME_2, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
       # axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_long2020 <- last_plot()

2022

col_pal <- c(#"#fef0d9",
             #"#fdcc8a"
             "#fc8d59",
             "#e34a33"
             #"#b30000"
  )

mob_indicators_1 %>% filter(year == "2022") %>%
  filter(distance_class == ">100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(NAME_2, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
       # axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_long2022 <- last_plot()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/argentina/barp_long2020.png", units="in", width=8, height=10, res=300)
  barp_long2020
dev.off()
null device 
          1 
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/argentina/barp_long2022.png", units="in", width=8, height=10, res=300)
  barp_long2022
dev.off()
null device 
          1 

Chile

Data

mobility data

## need to read this in 4 separate times - 202

# 2020 out
df20_b <- readRDS("/Volumes/RECAST/data/outputs/chile/movements/2020_04_mov.rds") %>% 
  mutate(GEOMETRY = NULL) %>% 
  dplyr::filter(country == "CL") %>% 
  st_as_sf(coords = c("end_lon", "end_lat"), 
                                      crs = 'EPSG:4326')

# 2022 out
df22_b <- readRDS("/Volumes/RECAST/data/outputs/chile/movements/2022_03_mov.rds") %>% 
  mutate(GEOMETRY = NULL) %>% 
  dplyr::filter(country == "CL") %>% 
  st_as_sf(coords = c("end_lon", "end_lat"), 
                                      crs = 'EPSG:4326')

boundary data

adm_shp <- st_read("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/Chile_shp/adm/province/PROVINCIAS_2020.shp")%>% 
  st_simplify(preserveTopology = T,
              dTolerance = 1000) %>% 
  st_make_valid() %>% 
  st_transform(crs = 'EPSG:4326')
Reading layer `PROVINCIAS_2020' from data source 
  `/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/Chile_shp/adm/province/PROVINCIAS_2020.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 56 features and 5 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -109.4488 ymin: -56.51273 xmax: -66.42812 ymax: -17.4984
Geodetic CRS:  SIRGAS-Chile 2002
adm1_shp <- st_read("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/Chile_shp/adm/region/REGIONES_2020.shp")%>% 
  st_simplify(preserveTopology = T,
              dTolerance = 1000) %>% 
  st_make_valid() %>% 
  st_transform(crs = 'EPSG:4326')
Reading layer `REGIONES_2020' from data source 
  `/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/Chile_shp/adm/region/REGIONES_2020.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 16 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -109.4488 ymin: -56.51273 xmax: -66.42812 ymax: -17.4984
Geodetic CRS:  SIRGAS-Chile 2002
region_shp <- st_read("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/Chile_shp/adm/country/gadm41_CHL_0.shp")%>% 
  st_simplify(preserveTopology = T,
              dTolerance = 1000) %>% 
  st_make_valid() %>% 
  st_transform(crs = 'EPSG:4326')
Reading layer `gadm41_CHL_0' from data source 
  `/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/Chile_shp/adm/country/gadm41_CHL_0.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 2 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -109.4549 ymin: -55.98 xmax: -66.41821 ymax: -17.49859
Geodetic CRS:  WGS 84

Data wrangling

df20_out <- df20_b %>% 
  filter(start_polygon_name == 'Santiago')
  
df22_out <- df22_b %>% 
  filter(start_polygon_name == 'Santiago')

Define distance

df20_out <- df20_out %>% mutate(
  distance_class = case_when(length_km < 100 ~ "<100",
                             length_km >= 100 ~ ">100"))

df22_out <- df22_out %>% mutate(
  distance_class = case_when(length_km < 100 ~ "<100",
                             length_km >= 100 ~ ">100"))

preserve a unique geometry

df20_out <- df20_out %>%
  group_by(end_polygon_name) %>%
  mutate(geometry = st_union(geometry)) %>%
  ungroup()

df22_out <- df22_out %>%
  group_by(end_polygon_name) %>%
  mutate(geometry = st_union(geometry)) %>%
  ungroup()

Sum of flows

outflows_df_20 <- df20_out %>% 
  filter(start_polygon_name != end_polygon_name) %>% 
  group_by(start_polygon_name, end_polygon_name, geometry, distance_class) %>% 
  dplyr::summarise(
    sum_outflow = sum(n_crisis, na.rm = T)) %>% 
  ungroup() 
`summarise()` has grouped output by 'start_polygon_name', 'end_polygon_name', 'geometry'. You can override using the `.groups` argument.
outflows_df_22 <- df22_out %>% 
  filter(start_polygon_name != end_polygon_name) %>% 
  group_by(start_polygon_name, end_polygon_name, geometry, distance_class) %>% 
  dplyr::summarise(
    sum_outflow = sum(n_crisis, na.rm = T)) %>% 
  ungroup() 
`summarise()` has grouped output by 'start_polygon_name', 'end_polygon_name', 'geometry'. You can override using the `.groups` argument.

Check alignment between data frames

p <- ggplot() + 
  geom_sf(data = adm_shp,
          color = "gray60", 
          size = 0.1) 

last_plot()

p <- p +
  geom_point(data = outflows_df_20,
    aes(geometry = geometry),
    stat = "sf_coordinates"
  ) 
last_plot()

Add year

outflows_df_20$year <- '2020'
outflows_df_22$year <- '2022'

Bind outflows

outflows_df <- rbind(outflows_df_20, outflows_df_22)

Join flows to polygons

mob_indicators_1 <- st_join(adm_shp, outflows_df)

classify data into quantiles

mob_indicators_1$new_jenk_class <- classify_intervals(mob_indicators_1$sum_outflow, n = 5, style = "quantile", factor = TRUE)
Warning: var has missing values, omitted in finding classes
outflow_labels_1 <- levels(mob_indicators_1$new_jenk_class)
outflow_labels_1 <- gsub("^.|.$", "",  outflow_labels_1)
outflow_labels_1 <- gsub("\\.[0-9]+", "",  outflow_labels_1)
outflow_labels_1 <- gsub("\\,", "-",  outflow_labels_1)
levels(mob_indicators_1$new_jenk_class) <- outflow_labels_1

# mob_indicators_1 <- mob_indicators_1 %>% 
  # mutate(new_jenk_class = str_replace(new_jenk_class, ",", "-"))

# change geometry
shp_reg <- region_shp %>% st_transform(crs = 'EPSG:4326')
mob_indicators_1$new_jenk_class <- mob_indicators_1$new_jenk_class %>% replace_na("10-420")
mob_indicators_1 <- na.omit(mob_indicators_1)

Plotting

Crop bounding box

bbox_new <- st_bbox(adm_shp) # current bounding box

xrange <- bbox_new$xmax - bbox_new$xmin # range of x values
yrange <- bbox_new$ymax - bbox_new$ymin # range of y values

bbox_new[1] <- bbox_new[1] + (0.6 * xrange) # xmin - left

bbox_new <- bbox_new %>%  # take the bounding box ...
  st_as_sfc() # ... and make it a sf polygon

ggplot() + 
  geom_sf(data = adm_shp,
          color = "gray60", 
          size = 0.1) +
  geom_point(data = outflows_df_20,
    aes(geometry = geometry),
    stat = "sf_coordinates",
    size = .1
  ) +
  coord_sf(xlim = st_coordinates(bbox_new)[c(1,2),1], # min & max of x values
           ylim = st_coordinates(bbox_new)[c(2,3),2]) + # min & max of y values
  theme_void()

Creating individual country map


shp_reg$centroid <- shp_reg %>% 
  st_centroid() %>% 
  st_geometry()
Warning: st_centroid assumes attributes are constant over geometries
padding_width <- 17
padding_height <- 22

ggplot(data = mob_indicators_1, 
                           aes(fill = new_jenk_class )) +
  geom_sf(col = "transparent", size = .2) + 
  coord_sf() +
  scale_fill_brewer(palette = "OrRd", 
                    direction = 1, 
                    labels = c("10-421", "422-1231", "1,232-3,370", "3,371-22,761", "> 22,761"),
                    na.value="black") +
  facet_grid(distance_class ~ year) +
  labs(title = "B. Chile",
       fill = "Number of out-moves") +
  theme_map() +
  guides(
    color='none',
    fill=guide_legend(
      keywidth = 4,
      keyheight = 1,
      nrow = 1,
      title.position="top",
      label.position="bottom"
    )
  ) +
  theme(plot.title = element_text(size = 16, face = "bold"),
        plot.margin=margin(1,0,1,0,"cm"),
        legend.title = element_markdown(
          size=10, face = "bold", hjust=0.5, lineheight=0.45,
          color="black",
          margin=margin(0,0,-0.2,0,"cm")
          ),
        legend.text = element_text(size = 9),
        legend.position = "bottom",
        legend.spacing.x = unit(0, 'cm'),
        panel.background = element_rect(fill = "gray99", colour = "gray99")
        ) +
    geom_sf(data = region_shp,
          col = "black", 
          size = 1,
          fill = "transparent") +
            coord_sf(xlim = c(shp_reg$centroid[[1]][1] - padding_width, 
                              shp_reg$centroid[[1]][1] + padding_width), 
                     ylim = c(shp_reg$centroid[[1]][2] - padding_height, 
                              shp_reg$centroid[[1]][2] + padding_height), 
                    expand = FALSE)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

outflow_plot_chi <- last_plot()

Saving country map

png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/chile/cloropleth-chi.png", units="in", width=8, height=10, res=300)
  last_plot()
dev.off()
null device 
          1 

Create map for Santiago

Short-distance

metro_region_shp <- adm1_shp %>% filter(REGION == "Metropolitana de Santiago" |
                                         REGION == "Valparaíso" | 
                                         REGION == "Libertador General Bernardo O'Higgins")

metro_region_shp$centroid <- metro_region_shp  %>% 
  st_centroid() %>% 
  st_geometry()
Warning: st_centroid assumes attributes are constant over geometries
padding_width <- 2
padding_height <- 1.8

col_pal <- c(#"#fef0d9",
             #"#fdcc8a",
             "#fc8d59",
             "#e34a33",
             "#b30000")

# 2020
mob_indicators_1 %>% filter(REGION == "Metropolitana de Santiago" |
                                         REGION == "Valparaíso" | 
                                         REGION == "Libertador General Bernardo O'Higgins") %>% 
  filter(year == "2020") %>% 
  filter(distance_class == "<100") %>% 
   ggplot(aes(fill = new_jenk_class)) +
     geom_sf(col = "white", size = .1) +
   coord_sf() +
   scale_fill_manual(values= col_pal) +
  # scale_fill_brewer(palette = "OrRd", 
  #                   direction = 1, 
  #                   labels = c("10-421", "422-1231", "1,232-3,370", "3,371-22,761", "> 22,761")) +
   theme_map() +
   theme(plot.title = element_text(size = 60),
         legend.position = "none",
         panel.background=element_rect(colour="black")
         ) +
   labs(title = "Santiago") +
    geom_sf(data = metro_region_shp,
          col = "black", 
          size = 1,
           fill = "transparent") +
            coord_sf(xlim = c(metro_region_shp$centroid[[3]][1] - padding_width,
                              metro_region_shp$centroid[[3]][1] + padding_width - .5),
                     ylim = c(metro_region_shp$centroid[[3]][2] - padding_height,
                              metro_region_shp$centroid[[3]][2] + padding_height),
                    expand = FALSE)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

sgto_map2020 <- last_plot()
# 2022

col_pal <- c(#"#fef0d9",
             #"#fdcc8a",
             #"#fc8d59",
             "#e34a33",
             "#b30000"
             )

mob_indicators_1 %>% filter(REGION == "Metropolitana de Santiago" |
                                         REGION == "Valparaíso" | 
                                         REGION == "Libertador General Bernardo O'Higgins") %>% 
  filter(year == "2022") %>% 
  filter(distance_class == "<100") %>% 
   ggplot(aes(fill = new_jenk_class)) +
     geom_sf(col = "white", size = .1) +
   coord_sf() +
   scale_fill_manual(values= col_pal) +
  # scale_fill_brewer(palette = "OrRd", 
  #                   direction = 1, 
  #                   labels = c("10-421", "422-1231", "1,232-3,370", "3,371-22,761", "> 22,761")) +
   theme_map() +
   theme(plot.title = element_text(size = 60),
         legend.position = "none",
         panel.background=element_rect(colour="black")
         ) +
   labs(title = "Santiago") +
    geom_sf(data = metro_region_shp,
          col = "black", 
          size = 1,
           fill = "transparent") +
            coord_sf(xlim = c(metro_region_shp$centroid[[3]][1] - padding_width,
                              metro_region_shp$centroid[[3]][1] + padding_width - .5),
                     ylim = c(metro_region_shp$centroid[[3]][2] - padding_height,
                              metro_region_shp$centroid[[3]][2] + padding_height),
                    expand = FALSE)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

sgto_map2022 <- last_plot()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/chile/cloropleth-sgto2020.png", units="in", width=8, height=10, res=300)
  sgto_map2020
dev.off()
null device 
          1 
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/chile/cloropleth-sgto2022.png", units="in", width=8, height=10, res=300)
  sgto_map2022
dev.off()
null device 
          1 

Create bar plot

Short-distance

col_pal <- c(#"#fef0d9",
             #"#fdcc8a",
             "#fc8d59",
             "#e34a33",
             "#b30000"
             )

mob_indicators_1$end_polygon_name[mob_indicators_1$end_polygon_name == "San Felipe de Aconcagua"] <- "San Felipe"

# 2020
mob_indicators_1 %>% filter(year == "2020") %>%
  filter(distance_class == "<100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(end_polygon_name, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
       # axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_short2020 <- last_plot()
col_pal <- c(#"#fef0d9",
             #"#fdcc8a",
             #"#fc8d59",
             "#e34a33",
             "#b30000"
             )
# 2022
mob_indicators_1 %>% filter(year == "2022") %>%
  filter(distance_class == "<100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  distinct(end_polygon_name, .keep_all=TRUE) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(end_polygon_name, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
        #axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_short2022 <- last_plot()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/chile/barp_short2020.png", units="in", width=8, height=10, res=300)
  barp_short2020
dev.off()
null device 
          1 
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/chile/barp_short2022.png", units="in", width=8, height=10, res=300)
  barp_short2022
dev.off()
null device 
          1 

Long-distance

col_pal <- c("#fef0d9",
             "#fdcc8a",
             "#fc8d59"
             #"#e34a33",
             #"#b30000"
             )

# 2020
mob_indicators_1 %>% filter(year == "2020") %>%
  filter(distance_class == ">100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  distinct(end_polygon_name, .keep_all=TRUE) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(end_polygon_name, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
       # axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_long2020 <- last_plot()
# 2022

col_pal <- c(#"#fef0d9",
             #"#fdcc8a",
             "#fc8d59",
             "#e34a33"
             #"#b30000"
             )

mob_indicators_1 %>% filter(year == "2022") %>%
  filter(distance_class == ">100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  distinct(end_polygon_name, .keep_all=TRUE) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(end_polygon_name, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
       # axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_long2022 <- last_plot()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/chile/barp_long2020.png", units="in", width=8, height=10, res=300)
  barp_long2020
dev.off()
null device 
          1 
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/chile/barp_long2022.png", units="in", width=8, height=10, res=300)
  barp_long2022
dev.off()
null device 
          1 

Mexico

mobility data

# 2020 out
df20_out <- readRDS("/Volumes/RECAST/data/outputs/mexico/movements/2020_04_mov.rds") %>% 
  mutate(GEOMETRY = NULL) %>% 
  dplyr::filter(country == "MX") %>% 
  st_as_sf(coords = c("end_lon", "end_lat"), 
                                      crs = 'EPSG:4326')

# 2022 out
df22_out <- readRDS("/Volumes/RECAST/data/outputs/mexico/movements/2022_03_mov.rds") %>% 
  mutate(GEOMETRY = NULL) %>% 
  dplyr::filter(country == "MX") %>% 
  st_as_sf(coords = c("end_lon", "end_lat"), 
                                      crs = 'EPSG:4326')

boundary data

# admin boundaries shape
adm_shp <- st_read("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_MEX_shp/gadm41_MEX_2.shp")%>% 
  st_simplify(preserveTopology = T,
              dTolerance = 1000) %>% 
  st_make_valid() %>% 
  st_transform(crs = 'EPSG:4326')
Reading layer `gadm41_MEX_2' from data source 
  `/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_MEX_shp/gadm41_MEX_2.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 2457 features and 13 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -118.3665 ymin: 14.53507 xmax: -86.71074 ymax: 32.71863
Geodetic CRS:  WGS 84
adm1_shp <- st_read("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_MEX_shp/gadm41_MEX_1.shp")%>% 
  st_simplify(preserveTopology = T,
              dTolerance = 1000) %>% 
  st_make_valid() %>% 
  st_transform(crs = 'EPSG:4326')
Reading layer `gadm41_MEX_1' from data source 
  `/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_MEX_shp/gadm41_MEX_1.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 32 features and 11 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -118.3665 ymin: 14.53507 xmax: -86.71074 ymax: 32.71863
Geodetic CRS:  WGS 84
# region shape
region_shp <- st_read("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_MEX_shp/gadm41_MEX_0.shp")%>% 
  st_simplify(preserveTopology = T,
              dTolerance = 1000) %>% 
  st_make_valid() %>% 
  st_transform(crs = 'EPSG:4326')
Reading layer `gadm41_MEX_0' from data source 
  `/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/data/maps/shapefiles/gadm41_MEX_shp/gadm41_MEX_0.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 2 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -118.3665 ymin: 14.53507 xmax: -86.71074 ymax: 32.71863
Geodetic CRS:  WGS 84

Data wrangling

# filter for start location as mexico city
df20_out <- df20_out %>%
  filter(start_polygon_name == 'Ciudad De México')

df22_out <- df22_out %>%
  filter(start_polygon_name == 'Ciudad De México')

Define distance

df20_out <- df20_out %>% mutate(
  distance_class = case_when(length_km < 100 ~ "<100",
                             length_km >= 100 ~ ">100"))

df22_out <- df22_out %>% mutate(
  distance_class = case_when(length_km < 100 ~ "<100",
                             length_km >= 100 ~ ">100"))

Sum of flows

# sum of outflows
outflows_df_20 <- df20_out %>% 
  filter(start_polygon_name != end_polygon_name) %>% 
  group_by(geometry, distance_class) %>% 
  dplyr::summarise(
    sum_outflow = sum(n_crisis, na.rm = T)) %>% 
  ungroup() 
`summarise()` has grouped output by 'geometry'. You can override using the `.groups` argument.
outflows_df_22 <- df22_out %>% 
  filter(start_polygon_name != end_polygon_name) %>% 
  group_by(geometry, distance_class) %>% 
  dplyr::summarise(
    sum_outflow = sum(n_crisis, na.rm = T)) %>% 
  ungroup() 
`summarise()` has grouped output by 'geometry'. You can override using the `.groups` argument.

Check alignment between data frames

# plot boundaries - test 
p <- ggplot() + 
  geom_sf(data = adm_shp,
          color = "gray60", 
          size = 0.1) 

last_plot()

# check geometry fits into either admin boundaries or region boundaries
p <- p +
  geom_point(data = outflows_df_20,
    aes(geometry = geometry),
    stat = "sf_coordinates"
  ) 
last_plot()

Add year

# assign a year to each
outflows_df_20$year <- '2020'
outflows_df_22$year <- '2022'

Bind outflows

outflows_df <- rbind(outflows_df_20, outflows_df_22)

Join flows to polygons

mob_indicators_1 <- st_join(adm_shp, outflows_df)

classify data into quantiles

mob_indicators_1$new_jenk_class <- classify_intervals(mob_indicators_1$sum_outflow, n = 5, style = "quantile", factor = TRUE)
Warning: var has missing values, omitted in finding classes
outflow_labels_1 <- levels(mob_indicators_1$new_jenk_class)
outflow_labels_1 <- gsub("^.|.$", "",  outflow_labels_1)
outflow_labels_1 <- gsub("\\.[0-9]+", "",  outflow_labels_1)
outflow_labels_1 <- gsub("\\,", "-",  outflow_labels_1)
levels(mob_indicators_1$new_jenk_class) <- outflow_labels_1

# mob_indicators_1 <- mob_indicators_1 %>% 
  # mutate(new_jenk_class = str_replace(new_jenk_class, ",", "-"))

# change geometry
shp_reg <- region_shp %>% st_transform(crs = 'EPSG:4326')
mob_indicators_1$new_jenk_class <- mob_indicators_1$new_jenk_class %>% replace_na("10-92")
mob_indicators_1 <- na.omit(mob_indicators_1)

Plotting

Creating individual country map


shp_reg$centroid <- shp_reg %>% 
  st_centroid() %>% 
  st_geometry()
Warning: st_centroid assumes attributes are constant over geometries
padding_width <- 17 
padding_height <- 22

new_y_labels <- c("Short-distance (<100km)", "Long-distance (>100km)")
names(new_y_labels) <- c("<100", ">100")

ggplot(data = mob_indicators_1, 
                           aes(fill = new_jenk_class )) +
  geom_sf(col = "transparent", size = .1) + 
  coord_sf() +
  scale_fill_brewer(palette = "OrRd", 
                    direction = 1, 
                    labels = c("10-92", "93-443", "444-1,654", "1,655-4,458", "> 4,458"), 
                    na.value="black") +
  facet_grid(distance_class ~ year, 
             labeller = labeller(distance_class = new_y_labels)) +
  labs(title = "C. Mexico",
       fill = "Number of out-moves") +
  theme_map() +
  guides(
    color='none',
    fill = guide_legend(
      keywidth = 4, 
      keyheight = 1,
      nrow = 1,
      title.position="top",
      label.position="bottom"
    )
  ) +
  theme(plot.title = element_text(size = 16, face = "bold"),
        plot.margin = margin(1,0,1,0,"cm"),
        legend.title = element_markdown(
          size=10, 
          face = "bold", 
          hjust=0.5, 
          lineheight=0.45,
          color="black",
          margin=margin(0,0,-0.2,0,"cm")
          ),
        legend.text = element_text(size = 8),
        legend.position = "bottom",
        legend.spacing.x = unit(0, 'cm'),
        panel.background = element_rect(fill = "gray99", colour = "gray99")
        ) +
    geom_sf(data = shp_reg,
          col = "black", 
          size = 1,
          fill = "transparent") +
            coord_sf(xlim = c(shp_reg$centroid[[1]][1] - padding_width, 
                              shp_reg$centroid[[1]][1] + padding_width), 
                     ylim = c(shp_reg$centroid[[1]][2] - padding_height - 7, 
                              shp_reg$centroid[[1]][2] + padding_height - 2), 
                    expand = FALSE)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

outflow_plot_mex <- last_plot()

Saving country map

png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/mexico/cloropleth-mex1.png", units="in", width=8, height=10, res=300)
  outflow_plot_mex
dev.off()
null device 
          1 

Create map for Mexico City

Short-distance

mxcity_region_shp <- adm1_shp %>% filter(NAME_1 == "Distrito Federal" |
                                           NAME_1 == "México" |
                                           NAME_1 == "Hidalgo" |
                                           NAME_1 == "Puebla" |
                                           NAME_1 == "Morelos" |
                                           NAME_1 == "Guerrero")

mxcity_region_shp$centroid <- mxcity_region_shp  %>% 
  st_centroid() %>% 
  st_geometry()
Warning: st_centroid assumes attributes are constant over geometries
padding_width <- 4.5
padding_height <- 3.5

col_pal <- c("#fef0d9",
             #"#fdcc8a",
             #"#fc8d59",
             #"#e34a33",
             "#b30000")

# 2020
mob_indicators_1 %>% filter(NAME_1 == "Guerrero" |
                              NAME_1 == "Hidalgo" |
                              NAME_1 == "México" |
                              NAME_1 == "Puebla" |
                              NAME_1 == "Tlaxcala") %>% 
  filter(year == "2020") %>% 
  filter(distance_class == "<100") %>% 
   ggplot(aes(fill = new_jenk_class)) +
     geom_sf(col = "white", size = .1) +
   coord_sf() +
   scale_fill_manual(values= col_pal) +
  # scale_fill_brewer(palette = "OrRd", 
  #                   direction = 1, 
  #                   labels = c("10-421", "422-1231", "1,232-3,370", "3,371-22,761", "> 22,761")) +
   theme_map() +
   theme(plot.title = element_text(size = 60),
         legend.position = "none",
         panel.background=element_rect(colour="black")
         ) +
   labs(title = "Mexico City") +
    geom_sf(data = mxcity_region_shp,
          col = "black", 
          size = 1,
           fill = "transparent") +
            coord_sf(xlim = c(mxcity_region_shp$centroid[[1]][1] - padding_width,
                              mxcity_region_shp$centroid[[1]][1] + padding_width - .5),
                     ylim = c(mxcity_region_shp$centroid[[1]][2] - padding_height,
                              mxcity_region_shp$centroid[[1]][2] + padding_height),
                    expand = FALSE)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

mxcity_map2020 <- last_plot()
# 2022

col_pal <- c("#fef0d9",
             "#fdcc8a",
             "#fc8d59",
             "#e34a33",
             "#b30000")

mob_indicators_1 %>% filter(NAME_1 == "Guerrero" |
                              NAME_1 == "Hidalgo" |
                              NAME_1 == "México" |
                              NAME_1 == "Puebla" |
                              NAME_1 == "Morelos" |
                              NAME_1 == "Tlaxcala") %>% 
  filter(year == "2022") %>% 
  filter(distance_class == "<100") %>% 
   ggplot(aes(fill = new_jenk_class)) +
     geom_sf(col = "white", size = .1) +
   coord_sf() +
   scale_fill_manual(values= col_pal) +
  # scale_fill_brewer(palette = "OrRd", 
  #                   direction = 1, 
  #                   labels = c("10-421", "422-1231", "1,232-3,370", "3,371-22,761", "> 22,761")) +
   theme_map() +
   theme(plot.title = element_text(size = 60),
         legend.position = "none",
         panel.background=element_rect(colour="black")
         ) +
   labs(title = "Mexico City") +
    geom_sf(data = mxcity_region_shp,
          col = "black", 
          size = 1,
           fill = "transparent") +
            coord_sf(xlim = c(mxcity_region_shp$centroid[[1]][1] - padding_width,
                              mxcity_region_shp$centroid[[1]][1] + padding_width - .5),
                     ylim = c(mxcity_region_shp$centroid[[1]][2] - padding_height,
                              mxcity_region_shp$centroid[[1]][2] + padding_height),
                    expand = FALSE)
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

mxcity_map2022 <- last_plot()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/mexico/cloropleth-mxcity2020.png", units="in", width=8, height=10, res=300)
  mxcity_map2020
dev.off()
null device 
          1 
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/mexico/cloropleth-mxcity2022.png", units="in", width=8, height=10, res=300)
  mxcity_map2022
dev.off()
null device 
          1 

Create bar plot

Short-distance

# 2020
col_pal <- c("#fef0d9",
             #"#fdcc8a",
             #"#fc8d59",
             #"#e34a33",
             "#b30000")

mob_indicators_1 %>% filter(year == "2020") %>%
  filter(distance_class == "<100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(NAME_2, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
       # axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_short2020 <- last_plot()
# 2022

 col_pal <- c(#"#fef0d9",
#              "#fdcc8a",
#              "#fc8d59",
#              "#e34a33",
             "#b30000")

mob_indicators_1 %>% filter(year == "2022") %>%
  filter(distance_class == "<100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  distinct(NAME_2, .keep_all=TRUE) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(NAME_2, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
        #axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_short2022 <- last_plot()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/mexico/barp_short2020.png", units="in", width=8, height=10, res=300)
  barp_short2020
dev.off()
null device 
          1 
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/mexico/barp_short2022.png", units="in", width=8, height=10, res=300)
  barp_short2022
dev.off()
null device 
          1 

Long-distance

# 2020
col_pal <- c(#"#fef0d9",
             #"#fdcc8a",
             #"#fc8d59",
             "#e34a33",
             "#b30000")

mob_indicators_1 %>% filter(year == "2020") %>%
  filter(distance_class == ">100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(NAME_2, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
       # axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_long2020 <- last_plot()
# 2022
col_pal <- c(#"#fef0d9",
             #"#fdcc8a",
             #"#fc8d59",
             #"#e34a33",
             "#b30000")

mob_indicators_1 %>% filter(year == "2022") %>%
  filter(distance_class == ">100") %>% 
  arrange(desc(sum_outflow)) %>% 
    mutate(outflow_total = sum(sum_outflow),
         outflow_percent = round( (sum_outflow/outflow_total)*100, 2 ) ) %>% 
  head(n = 10) %>% 
  ggplot(aes(x = reorder(NAME_2, outflow_percent), y = outflow_percent, fill = new_jenk_class)) + 
  geom_bar(stat="identity" ) + 
  scale_fill_manual(values= col_pal) +
  theme_tufte2() +
  coord_flip() +
  labs(title = "Top ten outflows",
       y = "Percent (%)") +
  theme(plot.margin=margin(1,0,1,1,"cm"),
        legend.position = "none",
        plot.title = element_text(size = 35),
        axis.text = element_text(size = 32),
        axis.title.y = element_blank(),
       # axis.title.x = element_blank(),
        axis.ticks.y = element_blank()) # Set custom y-axis labels


barp_long2022 <- last_plot()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/mexico/barp_long2020.png", units="in", width=8, height=10, res=300)
  barp_long2020
dev.off()
null device 
          1 
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/mexico/barp_long2022.png", units="in", width=8, height=10, res=300)
  barp_long2022
dev.off()
null device 
          1 

Saving combined maps

png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/cloropleth-map.png", units="in", width=8, height=10, res=300)
  outflow_plot_arg + outflow_plot_chi + outflow_plot_mex
dev.off()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/cloropleth-map1.png", units="in", width=8, height=10, res=300)
  wrap_plots(outflow_plot_arg,
             outflow_plot_chi,
             outflow_plot_mex)
dev.off()
png("/Users/franciscorowe/Dropbox/Francisco/Research/in_progress/recast/cepal-report/outputs/cloropleth-maps/cloropleth-map2.png", units="in", width=8, height=10, res=300)
  plot_grid(outflow_plot_arg, outflow_plot_chi, outflow_plot_mex, ncol=3, align="h")
dev.off()
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBEZXBlbmRlbmNpZXMKYGBge3J9CiMgZGF0YSB3cmFuZ2xpbmcKbGlicmFyeSh0aWR5dmVyc2UpCgojIHNwYXRpYWwgZGF0YSB3cmFuZ2xpbmcKbGlicmFyeShzZikKCiMgZGF0YSB2aXN1YWxpc2F0aW9uCmxpYnJhcnkodmlyaWRpcykgCgojIGZvcm1hdCBkYXRhIHZpc3VhbGlzYXRpb25zCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNob3d0ZXh0KQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShjbGFzc0ludCkKbGlicmFyeShnZ3RleHQpCgojIGNyZWF0ZSBtYXBzCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeSh0bWFwKQpsaWJyYXJ5KG1hcGRlY2spCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGNvd3Bsb3QpCmBgYAoKIyBTZXR0aW5nIHRoZW1lCgpTZXQgZm9udCBzdHlsZQpgYGB7cn0KIyBjbGVhbiB3b3Jrc3BhY2UKcm0obGlzdD1scygpKQojIGxvYWQgZm9udApmb250X2FkZF9nb29nbGUoIlJvYm90byBDb25kZW5zZWQiLCAicm9ib3RvY29uZGVuc2VkIikKIyBhdXRvbWF0aWNhbGx5IHVzZSBzaG93dGV4dCB0byByZW5kZXIgdGV4dApzaG93dGV4dF9hdXRvKCkKYGBgCgpUaGVtZSBmb3IgbWFwcwpgYGB7cn0KdGhlbWVfbWFwIDwtIGZ1bmN0aW9uKC4uLikgewogIHRoZW1lX3R1ZnRlKCkgKwogIHRoZW1lKAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAicm9ib3RvY29uZGVuc2VkIiwgc2l6ZSA9IDIwKSwKICAgICMgcmVtb3ZlIGFsbCBheGVzCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKQogICAgKQp9CmBgYAoKVGhlbWUgZm9yIHBsb3RzCgpgYGB7cn0KdGhlbWVfdHVmdGUyIDwtIGZ1bmN0aW9uKC4uLikgewogIHRoZW1lX3R1ZnRlKCkgKwogIHRoZW1lKAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAicm9ib3RvY29uZGVuc2VkIiwgc2l6ZSA9IDIwKSwKICAgICkKfQoKYGBgCgojIEFyZ2VudGluYQoKIyMgRGF0YQoKIyMjIG1vYmlsaXR5IGRhdGEKYGBge3J9CiMjIG5lZWQgdG8gcmVhZCB0aGlzIGluIDQgc2VwYXJhdGUgdGltZXMgLSAyMDIKCiMgMjAyMCBvdXQKZGYyMF9iIDwtIHJlYWRSRFMoIi9Wb2x1bWVzL1JFQ0FTVC9kYXRhL291dHB1dHMvYXJnZW50aW5hL21vdmVtZW50cy8yMDIwXzA0X21vdi5yZHMiKSAlPiUgCiAgbXV0YXRlKEdFT01FVFJZID0gTlVMTCkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoY291bnRyeSA9PSAiQVIiKSAlPiUgCiAgc3RfYXNfc2YoY29vcmRzID0gYygiZW5kX2xvbiIsICJlbmRfbGF0IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNycyA9ICdFUFNHOjQzMjYnKQoKIyAyMDIyIG91dApkZjIyX2IgPC0gcmVhZFJEUygiL1ZvbHVtZXMvUkVDQVNUL2RhdGEvb3V0cHV0cy9hcmdlbnRpbmEvbW92ZW1lbnRzLzIwMjJfMDNfbW92LnJkcyIpICU+JSAKICBtdXRhdGUoR0VPTUVUUlkgPSBOVUxMKSAlPiUgCiAgZHBseXI6OmZpbHRlcihjb3VudHJ5ID09ICJBUiIpICU+JSAKICBzdF9hc19zZihjb29yZHMgPSBjKCJlbmRfbG9uIiwgImVuZF9sYXQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JzID0gJ0VQU0c6NDMyNicpCmBgYAoKIyMjIGJvdW5kYXJ5IGRhdGEKYGBge3J9CmFkbV9zaHAgPC0gc3RfcmVhZCgiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9kYXRhL21hcHMvc2hhcGVmaWxlcy9nYWRtNDFfQVJHX3NocC9nYWRtNDFfQVJHXzIuc2hwIikgJT4lIAogIHN0X3NpbXBsaWZ5KHByZXNlcnZlVG9wb2xvZ3kgPSBULAogICAgICAgICAgICAgIGRUb2xlcmFuY2UgPSAxMDAwKSAlPiUgCiAgc3RfbWFrZV92YWxpZCgpICU+JSAKICBzdF90cmFuc2Zvcm0oY3JzID0gJ0VQU0c6NDMyNicpCgphZG0xX3NocCA8LSBzdF9yZWFkKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L2RhdGEvbWFwcy9zaGFwZWZpbGVzL2dhZG00MV9BUkdfc2hwL2dhZG00MV9BUkdfMS5zaHAiKSAlPiUgCiAgc3Rfc2ltcGxpZnkocHJlc2VydmVUb3BvbG9neSA9IFQsCiAgICAgICAgICAgICAgZFRvbGVyYW5jZSA9IDEwMDApICU+JSAKICBzdF9tYWtlX3ZhbGlkKCkgJT4lIAogIHN0X3RyYW5zZm9ybShjcnMgPSAnRVBTRzo0MzI2JykKCnJlZ2lvbl9zaHAgPC0gc3RfcmVhZCgiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9kYXRhL21hcHMvc2hhcGVmaWxlcy9nYWRtNDFfQVJHX3NocC9nYWRtNDFfQVJHXzAuc2hwIiklPiUgCiAgc3Rfc2ltcGxpZnkocHJlc2VydmVUb3BvbG9neSA9IFQsCiAgICAgICAgICAgICAgZFRvbGVyYW5jZSA9IDEwMDApICU+JSAKICBzdF9tYWtlX3ZhbGlkKCkgJT4lIAogIHN0X3RyYW5zZm9ybShjcnMgPSAnRVBTRzo0MzI2JykKYGBgCgojIyBEYXRhIHdyYW5nbGluZwpgYGB7cn0KYXJlYV9uYW1lcyA8LSBjKCJKb3PDqSBDLiBQYXoiLCAiU2FuIE1pZ3VlbCIsICJNb3LDs24iLCAiQ2FwaXRhbCBGZWRlcmFsIiwgIkVzdGViYW4gRWNoZXZlcnLDrWEiLCAiRmxvcmVuY2lvIFZhcmVsYSIpCgojIGZpbHRlciBmb3IgdGhlIGFyZWEgbmFtZXMgd2hpY2ggYXJlIHdpdGhpbiBCdWVub3MgQWlyZXMKZGYyMF9vdXQgPC0gZGYyMF9iICU+JSBkcGx5cjo6ZmlsdGVyKHN0YXJ0X3BvbHlnb25fbmFtZSAlaW4lIGFyZWFfbmFtZXMpCmRmMjJfb3V0IDwtIGRmMjJfYiAlPiUgZHBseXI6OmZpbHRlcihzdGFydF9wb2x5Z29uX25hbWUgJWluJSBhcmVhX25hbWVzKQoKZGYyMF9vdXQkc3RhcnRfcG9seWdvbl9uYW1lIDwtICdCdWVub3MgQWlyZXMnCmRmMjJfb3V0JHN0YXJ0X3BvbHlnb25fbmFtZSA8LSAnQnVlbm9zIEFpcmVzJwoKZGYyMF9vdXQgPC0gZGYyMF9vdXQgJT4lIGZpbHRlcighZW5kX3BvbHlnb25fbmFtZSAlaW4lIGFyZWFfbmFtZXMpCmRmMjJfb3V0IDwtIGRmMjJfb3V0ICU+JSBmaWx0ZXIoIWVuZF9wb2x5Z29uX25hbWUgJWluJSBhcmVhX25hbWVzKQpgYGAKCiMjIyBEZWZpbmUgZGlzdGFuY2UKYGBge3J9CmRmMjBfb3V0IDwtIGRmMjBfb3V0ICU+JSBtdXRhdGUoCiAgZGlzdGFuY2VfY2xhc3MgPSBjYXNlX3doZW4obGVuZ3RoX2ttIDwgMTAwIH4gIjwxMDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9rbSA+PSAxMDAgfiAiPjEwMCIpKQoKZGYyMl9vdXQgPC0gZGYyMl9vdXQgJT4lIG11dGF0ZSgKICBkaXN0YW5jZV9jbGFzcyA9IGNhc2Vfd2hlbihsZW5ndGhfa20gPCAxMDAgfiAiPDEwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2ttID49IDEwMCB+ICI+MTAwIikpCgpgYGAKCiMjIyBwcmVzZXJ2ZSBhIHVuaXF1ZSBnZW9tZXRyeQpgYGB7cn0KZGYyMF9vdXQgPC0gZGYyMF9vdXQgJT4lCiAgZ3JvdXBfYnkoZW5kX3BvbHlnb25fbmFtZSkgJT4lCiAgbXV0YXRlKGdlb21ldHJ5ID0gc3RfdW5pb24oZ2VvbWV0cnkpKSAlPiUKICB1bmdyb3VwKCkKCmRmMjJfb3V0IDwtIGRmMjJfb3V0ICU+JQogIGdyb3VwX2J5KGVuZF9wb2x5Z29uX25hbWUpICU+JQogIG11dGF0ZShnZW9tZXRyeSA9IHN0X3VuaW9uKGdlb21ldHJ5KSkgJT4lCiAgdW5ncm91cCgpCmBgYAoKIyMjIFN1bSBvZiBmbG93cwpgYGB7cn0Kb3V0Zmxvd3NfZGZfMjAgPC0gZGYyMF9vdXQgJT4lIAogIGZpbHRlcihzdGFydF9wb2x5Z29uX25hbWUgIT0gZW5kX3BvbHlnb25fbmFtZSkgJT4lIAogIGdyb3VwX2J5KHN0YXJ0X3BvbHlnb25fbmFtZSwgZW5kX3BvbHlnb25fbmFtZSwgZ2VvbWV0cnksIGRpc3RhbmNlX2NsYXNzKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZSgKICAgIHN1bV9vdXRmbG93ID0gc3VtKG5fY3Jpc2lzLCBuYS5ybSA9IFQpKSAlPiUgCiAgdW5ncm91cCgpIAoKb3V0Zmxvd3NfZGZfMjIgPC0gZGYyMl9vdXQgJT4lIAogIGZpbHRlcihzdGFydF9wb2x5Z29uX25hbWUgIT0gZW5kX3BvbHlnb25fbmFtZSkgJT4lIAogIGdyb3VwX2J5KHN0YXJ0X3BvbHlnb25fbmFtZSwgZW5kX3BvbHlnb25fbmFtZSwgZ2VvbWV0cnksIGRpc3RhbmNlX2NsYXNzKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZSgKICAgIHN1bV9vdXRmbG93ID0gc3VtKG5fY3Jpc2lzLCBuYS5ybSA9IFQpKSAlPiUgCiAgdW5ncm91cCgpIApgYGAKCiMjIyBDaGVjayBhbGlnbm1lbnQgYmV0d2VlbiBkYXRhIGZyYW1lcwpgYGB7cn0KcCA8LSBnZ3Bsb3QoKSArIAogIGdlb21fc2YoZGF0YSA9IGFkbV9zaHAsCiAgICAgICAgICBjb2xvciA9ICJncmF5NjAiLCAKICAgICAgICAgIHNpemUgPSAwLjEpIAoKbGFzdF9wbG90KCkKYGBgCgpgYGB7cn0KcCA8LSBwICsKICBnZW9tX3BvaW50KGRhdGEgPSBvdXRmbG93c19kZl8yMCwKICAgIGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwKICAgIHN0YXQgPSAic2ZfY29vcmRpbmF0ZXMiCiAgKSAKbGFzdF9wbG90KCkKYGBgCgojIyMgQWRkIHllYXIKYGBge3J9Cm91dGZsb3dzX2RmXzIwJHllYXIgPC0gJzIwMjAnCm91dGZsb3dzX2RmXzIyJHllYXIgPC0gJzIwMjInCmBgYAoKIyMjIEJpbmQgb3V0Zmxvd3MKYGBge3J9Cm91dGZsb3dzX2RmIDwtIHJiaW5kKG91dGZsb3dzX2RmXzIwLCBvdXRmbG93c19kZl8yMikKYGBgCgojIyMgSm9pbiBmbG93cyB0byBwb2x5Z29ucwpgYGB7cn0KbW9iX2luZGljYXRvcnNfMSA8LSBzdF9qb2luKGFkbV9zaHAsIG91dGZsb3dzX2RmKQpgYGAKCiMjIyBjbGFzc2lmeSBkYXRhIGludG8gcXVhbnRpbGVzCmBgYHtyfQptb2JfaW5kaWNhdG9yc18xJG5ld19qZW5rX2NsYXNzIDwtIGNsYXNzaWZ5X2ludGVydmFscyhtb2JfaW5kaWNhdG9yc18xJHN1bV9vdXRmbG93LCBuID0gNSwgc3R5bGUgPSAicXVhbnRpbGUiLCBmYWN0b3IgPSBUUlVFKQoKb3V0Zmxvd19sYWJlbHNfMSA8LSBsZXZlbHMobW9iX2luZGljYXRvcnNfMSRuZXdfamVua19jbGFzcykKb3V0Zmxvd19sYWJlbHNfMSA8LSBnc3ViKCJeLnwuJCIsICIiLCAgb3V0Zmxvd19sYWJlbHNfMSkKb3V0Zmxvd19sYWJlbHNfMSA8LSBnc3ViKCJcXC5bMC05XSsiLCAiIiwgIG91dGZsb3dfbGFiZWxzXzEpCm91dGZsb3dfbGFiZWxzXzEgPC0gZ3N1YigiXFwsIiwgIi0iLCAgb3V0Zmxvd19sYWJlbHNfMSkKbGV2ZWxzKG1vYl9pbmRpY2F0b3JzXzEkbmV3X2plbmtfY2xhc3MpIDwtIG91dGZsb3dfbGFiZWxzXzEKCiMgbW9iX2luZGljYXRvcnNfMSA8LSBtb2JfaW5kaWNhdG9yc18xICU+JSAKICAjIG11dGF0ZShuZXdfamVua19jbGFzcyA9IHN0cl9yZXBsYWNlKG5ld19qZW5rX2NsYXNzLCAiLCIsICItIikpCgojIGNoYW5nZSBnZW9tZXRyeQpzaHBfcmVnIDwtIHJlZ2lvbl9zaHAgJT4lIHN0X3RyYW5zZm9ybShjcnMgPSAnRVBTRzo0MzI2JykKYGBgCgpgYGB7cn0KbW9iX2luZGljYXRvcnNfMSRuZXdfamVua19jbGFzcyA8LSBtb2JfaW5kaWNhdG9yc18xJG5ld19qZW5rX2NsYXNzICU+JSByZXBsYWNlX25hKCIxMC0zMiIpCmBgYAoKCmBgYHtyfQptb2JfaW5kaWNhdG9yc18xIDwtIG5hLm9taXQobW9iX2luZGljYXRvcnNfMSkKYGBgCgoKIyMgUGxvdHRpbmcKCiMjIyBDcmVhdGluZyBpbmRpdmlkdWFsIGNvdW50cnkgbWFwCmBgYHtyfQoKc2hwX3JlZyRjZW50cm9pZCA8LSBzaHBfcmVnICU+JSAKICBzdF9jZW50cm9pZCgpICU+JSAKICBzdF9nZW9tZXRyeSgpCgpwYWRkaW5nX3dpZHRoIDwtIDE3IApwYWRkaW5nX2hlaWdodCA8LSAyMgoKZ2dwbG90KGRhdGEgPSBtb2JfaW5kaWNhdG9yc18xLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGZpbGwgPSBuZXdfamVua19jbGFzcyApKSArCiAgZ2VvbV9zZihjb2wgPSAid2hpdGUiLCBzaXplID0gLjIpICsgCiAgY29vcmRfc2YoKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJPclJkIiwgCiAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gMSwgCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMTAtMzIiLCAiMzItMjQyIiwgIjI0My0xLDY0MCIsICIxNjQxLTMwLDI5MSIsICI+IDMwLDI5MiIpLCAKICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZT0iYmxhY2siKSArCiAgZmFjZXRfZ3JpZChkaXN0YW5jZV9jbGFzcyB+IHllYXIpICsKICBsYWJzKHRpdGxlID0gIkEuIEFyZ2VudGluYSIsCiAgICAgICBmaWxsID0gIk51bWJlciBvZiBvdXQtbW92ZXMiKSArCiAgdGhlbWVfbWFwKCkgKwogIGd1aWRlcygKICAgIGNvbG9yPSdub25lJywKICAgIGZpbGwgPSBndWlkZV9sZWdlbmQoCiAgICAgIGtleXdpZHRoID0gNCwgCiAgICAgIGtleWhlaWdodCA9IDEsCiAgICAgIG5yb3cgPSAxLAogICAgICB0aXRsZS5wb3NpdGlvbj0idG9wIiwKICAgICAgbGFiZWwucG9zaXRpb249ImJvdHRvbSIKICAgICkKICApICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5tYXJnaW49bWFyZ2luKDEsMCwxLDAsImNtIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9tYXJrZG93bigKICAgICAgICAgIHNpemU9MTAsIGZhY2UgPSAiYm9sZCIsIGhqdXN0PTAuNSwgbGluZWhlaWdodD0wLjQ1LAogICAgICAgICAgY29sb3I9ImJsYWNrIiwKICAgICAgICAgIG1hcmdpbj1tYXJnaW4oMCwwLC0wLjIsMCwiY20iKQogICAgICAgICAgKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoMCwgJ2NtJyksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXk5OCIsIGNvbG91ciA9ICJncmF5OTgiKQogICAgICAgICkgKwogICAgZ2VvbV9zZihkYXRhID0gc2hwX3JlZywKICAgICAgICAgIGNvbCA9ICJibGFjayIsIAogICAgICAgICAgc2l6ZSA9IDEsCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IikgKwogICAgICAgICAgICBjb29yZF9zZih4bGltID0gYyhzaHBfcmVnJGNlbnRyb2lkW1sxXV1bMV0gLSBwYWRkaW5nX3dpZHRoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hwX3JlZyRjZW50cm9pZFtbMV1dWzFdICsgcGFkZGluZ193aWR0aCksIAogICAgICAgICAgICMgICAgICAgICAgeWxpbSA9IGMoc2hwX3JlZyRjZW50cm9pZFtbMV1dWzJdIC0gcGFkZGluZ19oZWlnaHQsIAogICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgc2hwX3JlZyRjZW50cm9pZFtbMV1dWzJdICsgcGFkZGluZ19oZWlnaHQpLCAKICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBGQUxTRSkKCm91dGZsb3dfcGxvdF9hcmcgPC0gbGFzdF9wbG90KCkKYGBgCgojIyMgU2F2aW5nIG1hcApgYGB7cn0KcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL2FyZ2VudGluYS9jbG9yb3BsZXRoLWFyZy5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHJlcz0zMDApCiAgb3V0Zmxvd19wbG90X2FyZwpkZXYub2ZmKCkKYGBgCgojIyMgQ3JlYXRlIG1hcCBmb3IgQnVlbm9zIEFpcmVzCgpTaG9ydC1kaXN0YW5jZQpgYGB7cn0KYmFfZGVwYXJtZW50X3NocCA8LSBhZG0xX3NocCAlPiUgZmlsdGVyKE5BTUVfMSA9PSAiQnVlbm9zIEFpcmVzIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BTUVfMSA9PSAiQ2l1ZGFkIGRlIEJ1ZW5vcyBBaXJlcyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQU1FXzEgPT0gIkVudHJlIFLDrW9zIikKCmJhX2RlcGFybWVudF9zaHAkY2VudHJvaWQgPC0gYmFfZGVwYXJtZW50X3NocCAlPiUgCiAgc3RfY2VudHJvaWQoKSAlPiUgCiAgc3RfZ2VvbWV0cnkoKQoKcGFkZGluZ193aWR0aCA8LSAzLjUgCnBhZGRpbmdfaGVpZ2h0IDwtIDMuMgoKIyAyMDIwCm1vYl9pbmRpY2F0b3JzXzEgJT4lIGZpbHRlcihOQU1FXzEgPT0gIkJ1ZW5vcyBBaXJlcyJ8IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQU1FXzEgPT0gIkNpdWRhZCBkZSBCdWVub3MgQWlyZXMiIHwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BTUVfMSA9PSAiRW50cmUgUsOtb3MiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFNRV8xID09ICJDw7NyZG9iYSIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQU1FXzEgPT0gIlNhbnRhIEZlIikgJT4lIAogIGZpbHRlcih5ZWFyID09ICIyMDIwIikgJT4lIAogIGZpbHRlcihkaXN0YW5jZV9jbGFzcyA9PSAiPDEwMCIpICU+JSAKICAgZ2dwbG90KGFlcyhmaWxsID0gbmV3X2plbmtfY2xhc3MpKSArCiAgICAgZ2VvbV9zZihjb2wgPSAid2hpdGUiLCBzaXplID0gLjEpICsKICAgY29vcmRfc2YoKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJPclJkIiwgCiAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gMSwgCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMTAtMzIiLCAiMzItMjQyIiwgIjI0My0xLDY0MCIsICIxNjQxLTMwLDI5MSIsICI+IDMwLDI5MiIpKSArCiAgIHRoZW1lX21hcCgpICsKICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNjApLAogICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGNvbG91cj0iYmxhY2siKQogICAgICAgICApICsKICAgbGFicyh0aXRsZSA9ICJCdWVub3MgQWlyZXMiKSArCiAgICBnZW9tX3NmKGRhdGEgPSBiYV9kZXBhcm1lbnRfc2hwLAogICAgICAgICAgY29sID0gImJsYWNrIiwgCiAgICAgICAgICBzaXplID0gMSwKICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiKSArCiAgICAgICAgICAgIGNvb3JkX3NmKHhsaW0gPSBjKGJhX2RlcGFybWVudF9zaHAkY2VudHJvaWRbWzFdXVsxXSAtIC0uNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhX2RlcGFybWVudF9zaHAkY2VudHJvaWRbWzFdXVsxXSArIHBhZGRpbmdfd2lkdGgpLCAKICAgICAgICAgICAgICAgICAgICAgeWxpbSA9IGMoYmFfZGVwYXJtZW50X3NocCRjZW50cm9pZFtbMV1dWzJdIC0gLS41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFfZGVwYXJtZW50X3NocCRjZW50cm9pZFtbMV1dWzJdICsgcGFkZGluZ19oZWlnaHQpLCAKICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBGQUxTRSkKCmJhX21hcDIwMjAgPC0gbGFzdF9wbG90KCkKCiMgMjAyMgptb2JfaW5kaWNhdG9yc18xICU+JSBmaWx0ZXIoTkFNRV8xID09ICJCdWVub3MgQWlyZXMifCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFNRV8xID09ICJDaXVkYWQgZGUgQnVlbm9zIEFpcmVzIiB8IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQU1FXzEgPT0gIkVudHJlIFLDrW9zIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BTUVfMSA9PSAiQ8OzcmRvYmEiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFNRV8xID09ICJTYW50YSBGZSIpICU+JSAKICBmaWx0ZXIoeWVhciA9PSAiMjAyMiIpICU+JSAKICBmaWx0ZXIoZGlzdGFuY2VfY2xhc3MgPT0gIjwxMDAiKSAlPiUgCiAgIGdncGxvdChhZXMoZmlsbCA9IG5ld19qZW5rX2NsYXNzKSkgKwogICAgIGdlb21fc2YoY29sID0gIndoaXRlIiwgc2l6ZSA9IC4xKSArCiAgIGNvb3JkX3NmKCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiT3JSZCIsIAogICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IDEsIAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjEwLTMyIiwgIjMyLTI0MiIsICIyNDMtMSw2NDAiLCAiMTY0MS0zMCwyOTEiLCAiPiAzMCwyOTIiKSkgKwogICB0aGVtZV9tYXAoKSArCiAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYwKSwKICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kPWVsZW1lbnRfcmVjdChjb2xvdXI9ImJsYWNrIikKICAgICAgICAgKSArCiAgIGxhYnModGl0bGUgPSAiQnVlbm9zIEFpcmVzIikgKwogICAgZ2VvbV9zZihkYXRhID0gYmFfZGVwYXJtZW50X3NocCwKICAgICAgICAgIGNvbCA9ICJibGFjayIsIAogICAgICAgICAgc2l6ZSA9IDEsCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IikgKwogICAgICAgICAgICBjb29yZF9zZih4bGltID0gYyhiYV9kZXBhcm1lbnRfc2hwJGNlbnRyb2lkW1sxXV1bMV0gLSAtLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYV9kZXBhcm1lbnRfc2hwJGNlbnRyb2lkW1sxXV1bMV0gKyBwYWRkaW5nX3dpZHRoKSwgCiAgICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKGJhX2RlcGFybWVudF9zaHAkY2VudHJvaWRbWzFdXVsyXSAtIC0uNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhX2RlcGFybWVudF9zaHAkY2VudHJvaWRbWzFdXVsyXSArIHBhZGRpbmdfaGVpZ2h0KSwgCiAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gRkFMU0UpCgpiYV9tYXAyMDIyIDwtIGxhc3RfcGxvdCgpCgpgYGAKYGBge3J9CnBuZygiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9vdXRwdXRzL2Nsb3JvcGxldGgtbWFwcy9hcmdlbnRpbmEvY2xvcm9wbGV0aC1iYTIwMjAucG5nIiwgdW5pdHM9ImluIiwgd2lkdGg9OCwgaGVpZ2h0PTEwLCByZXM9MzAwKQogIGJhX21hcDIwMjAKZGV2Lm9mZigpCgpwbmcoIi9Vc2Vycy9mcmFuY2lzY29yb3dlL0Ryb3Bib3gvRnJhbmNpc2NvL1Jlc2VhcmNoL2luX3Byb2dyZXNzL3JlY2FzdC9jZXBhbC1yZXBvcnQvb3V0cHV0cy9jbG9yb3BsZXRoLW1hcHMvYXJnZW50aW5hL2Nsb3JvcGxldGgtYmEyMDIyLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBiYV9tYXAyMDIyCmRldi5vZmYoKQpgYGAKCiMjIyBDcmVhdGUgYmFyIHBsb3QKCiMjIyMgU2hvcnQtZGlzdGFuY2UKYGBge3J9CmNvbF9wYWwgPC0gYygjIiNmZWYwZDkiLAogICAgICAgICAgICAgIyIjZmRjYzhhIiwKICAgICAgICAgICAgICMiI2ZjOGQ1OSIsCiAgICAgICAgICAgICAiI2UzNGEzMyIsCiAgICAgICAgICAgICAiI2IzMDAwMCIpCgojIDIwMjAKbW9iX2luZGljYXRvcnNfMSAlPiUgZmlsdGVyKHllYXIgPT0gIjIwMjAiKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2VfY2xhc3MgPT0gIjwxMDAiKSAlPiUgCiAgYXJyYW5nZShkZXNjKHN1bV9vdXRmbG93KSkgJT4lIAogICAgbXV0YXRlKG91dGZsb3dfdG90YWwgPSBzdW0oc3VtX291dGZsb3cpLAogICAgICAgICBvdXRmbG93X3BlcmNlbnQgPSByb3VuZCggKHN1bV9vdXRmbG93L291dGZsb3dfdG90YWwpKjEwMCwgMiApICkgJT4lIAogICAgZGlzdGluY3QoZW5kX3BvbHlnb25fbmFtZSwgLmtlZXBfYWxsPVRSVUUpICU+JSAKICBoZWFkKG4gPSAxMCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoZW5kX3BvbHlnb25fbmFtZSwgb3V0Zmxvd19wZXJjZW50KSwgeSA9IG91dGZsb3dfcGVyY2VudCwgZmlsbCA9IG5ld19qZW5rX2NsYXNzKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIgKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sX3BhbCkgKwogIHRoZW1lX3R1ZnRlMigpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiVG9wIHRlbiBvdXRmbG93cyIsCiAgICAgICB5ID0gIlBlcmNlbnQgKCUpIikgKwogIHRoZW1lKHBsb3QubWFyZ2luPW1hcmdpbigxLDAsMSwxLCJjbSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzNSksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIyBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpKSAjIFNldCBjdXN0b20geS1heGlzIGxhYmVscwoKYmFycF9zaG9ydDIwMjAgPC0gbGFzdF9wbG90KCkKCiMgMjAyMgptb2JfaW5kaWNhdG9yc18xICU+JSBmaWx0ZXIoeWVhciA9PSAiMjAyMiIpICU+JQogIGZpbHRlcihkaXN0YW5jZV9jbGFzcyA9PSAiPDEwMCIpICU+JSAKICBhcnJhbmdlKGRlc2Moc3VtX291dGZsb3cpKSAlPiUgCiAgICBtdXRhdGUob3V0Zmxvd190b3RhbCA9IHN1bShzdW1fb3V0ZmxvdyksCiAgICAgICAgIG91dGZsb3dfcGVyY2VudCA9IHJvdW5kKCAoc3VtX291dGZsb3cvb3V0Zmxvd190b3RhbCkqMTAwLCAyICkgKSAlPiUgCiAgZGlzdGluY3QoZW5kX3BvbHlnb25fbmFtZSwgLmtlZXBfYWxsPVRSVUUpICU+JSAKICBoZWFkKG4gPSAxMCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoZW5kX3BvbHlnb25fbmFtZSwgb3V0Zmxvd19wZXJjZW50KSwgeSA9IG91dGZsb3dfcGVyY2VudCwgZmlsbCA9IG5ld19qZW5rX2NsYXNzKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIgKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sX3BhbCkgKwogIHRoZW1lX3R1ZnRlMigpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiVG9wIHRlbiBvdXRmbG93cyIsCiAgICAgICB5ID0gIlBlcmNlbnQgKCUpIikgKwogIHRoZW1lKHBsb3QubWFyZ2luPW1hcmdpbigxLDAsMSwxLCJjbSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzNSksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICNheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpKSAjIFNldCBjdXN0b20geS1heGlzIGxhYmVscwoKYmFycF9zaG9ydDIwMjIgPC0gbGFzdF9wbG90KCkKYGBgCgpgYGB7cn0KcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL2FyZ2VudGluYS9iYXJwX3Nob3J0MjAyMC5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHJlcz0zMDApCiAgYmFycF9zaG9ydDIwMjAKZGV2Lm9mZigpCgpwbmcoIi9Vc2Vycy9mcmFuY2lzY29yb3dlL0Ryb3Bib3gvRnJhbmNpc2NvL1Jlc2VhcmNoL2luX3Byb2dyZXNzL3JlY2FzdC9jZXBhbC1yZXBvcnQvb3V0cHV0cy9jbG9yb3BsZXRoLW1hcHMvYXJnZW50aW5hL2JhcnBfc2hvcnQyMDIyLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBiYXJwX3Nob3J0MjAyMgpkZXYub2ZmKCkKYGBgCgojIyMjIExvbmctZGlzdGFuY2UKMjAyMApgYGB7cn0KY29sX3BhbCA8LSBjKCIjZmVmMGQ5IiwKICAgICAgICAgICAgICIjZmRjYzhhIgogICAgICAgICAgICAgIyIjZmM4ZDU5IgogICAgICAgICAgICAgIyIjZTM0YTMzIiwKICAgICAgICAgICAgICMiI2IzMDAwMCIKICApCgptb2JfaW5kaWNhdG9yc18xICU+JSBmaWx0ZXIoeWVhciA9PSAiMjAyMCIpICU+JQogIGZpbHRlcihkaXN0YW5jZV9jbGFzcyA9PSAiPjEwMCIpICU+JSAKICBhcnJhbmdlKGRlc2Moc3VtX291dGZsb3cpKSAlPiUgCiAgICBtdXRhdGUob3V0Zmxvd190b3RhbCA9IHN1bShzdW1fb3V0ZmxvdyksCiAgICAgICAgIG91dGZsb3dfcGVyY2VudCA9IHJvdW5kKCAoc3VtX291dGZsb3cvb3V0Zmxvd190b3RhbCkqMTAwLCAyICkgKSAlPiUgCiAgaGVhZChuID0gMTApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKE5BTUVfMiwgb3V0Zmxvd19wZXJjZW50KSwgeSA9IG91dGZsb3dfcGVyY2VudCwgZmlsbCA9IG5ld19qZW5rX2NsYXNzKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIgKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sX3BhbCkgKwogIHRoZW1lX3R1ZnRlMigpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiVG9wIHRlbiBvdXRmbG93cyIsCiAgICAgICB5ID0gIlBlcmNlbnQgKCUpIikgKwogIHRoZW1lKHBsb3QubWFyZ2luPW1hcmdpbigxLDAsMSwxLCJjbSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzNSksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIyBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpKSAjIFNldCBjdXN0b20geS1heGlzIGxhYmVscwoKYmFycF9sb25nMjAyMCA8LSBsYXN0X3Bsb3QoKQpgYGAKCjIwMjIKYGBge3J9CmNvbF9wYWwgPC0gYygjIiNmZWYwZDkiLAogICAgICAgICAgICAgIyIjZmRjYzhhIgogICAgICAgICAgICAgIiNmYzhkNTkiLAogICAgICAgICAgICAgIiNlMzRhMzMiCiAgICAgICAgICAgICAjIiNiMzAwMDAiCiAgKQoKbW9iX2luZGljYXRvcnNfMSAlPiUgZmlsdGVyKHllYXIgPT0gIjIwMjIiKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2VfY2xhc3MgPT0gIj4xMDAiKSAlPiUgCiAgYXJyYW5nZShkZXNjKHN1bV9vdXRmbG93KSkgJT4lIAogICAgbXV0YXRlKG91dGZsb3dfdG90YWwgPSBzdW0oc3VtX291dGZsb3cpLAogICAgICAgICBvdXRmbG93X3BlcmNlbnQgPSByb3VuZCggKHN1bV9vdXRmbG93L291dGZsb3dfdG90YWwpKjEwMCwgMiApICkgJT4lIAogIGhlYWQobiA9IDEwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihOQU1FXzIsIG91dGZsb3dfcGVyY2VudCksIHkgPSBvdXRmbG93X3BlcmNlbnQsIGZpbGwgPSBuZXdfamVua19jbGFzcykpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiICkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGNvbF9wYWwpICsKICB0aGVtZV90dWZ0ZTIoKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlRvcCB0ZW4gb3V0Zmxvd3MiLAogICAgICAgeSA9ICJQZXJjZW50ICglKSIpICsKICB0aGVtZShwbG90Lm1hcmdpbj1tYXJnaW4oMSwwLDEsMSwiY20iKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzUpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICMgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgIyBTZXQgY3VzdG9tIHktYXhpcyBsYWJlbHMKCmJhcnBfbG9uZzIwMjIgPC0gbGFzdF9wbG90KCkKYGBgCgpgYGB7cn0KcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL2FyZ2VudGluYS9iYXJwX2xvbmcyMDIwLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBiYXJwX2xvbmcyMDIwCmRldi5vZmYoKQoKcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL2FyZ2VudGluYS9iYXJwX2xvbmcyMDIyLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBiYXJwX2xvbmcyMDIyCmRldi5vZmYoKQpgYGAKCgojIENoaWxlCgojIyBEYXRhCgojIyMgbW9iaWxpdHkgZGF0YQpgYGB7cn0KIyMgbmVlZCB0byByZWFkIHRoaXMgaW4gNCBzZXBhcmF0ZSB0aW1lcyAtIDIwMgoKIyAyMDIwIG91dApkZjIwX2IgPC0gcmVhZFJEUygiL1ZvbHVtZXMvUkVDQVNUL2RhdGEvb3V0cHV0cy9jaGlsZS9tb3ZlbWVudHMvMjAyMF8wNF9tb3YucmRzIikgJT4lIAogIG11dGF0ZShHRU9NRVRSWSA9IE5VTEwpICU+JSAKICBkcGx5cjo6ZmlsdGVyKGNvdW50cnkgPT0gIkNMIikgJT4lIAogIHN0X2FzX3NmKGNvb3JkcyA9IGMoImVuZF9sb24iLCAiZW5kX2xhdCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcnMgPSAnRVBTRzo0MzI2JykKCiMgMjAyMiBvdXQKZGYyMl9iIDwtIHJlYWRSRFMoIi9Wb2x1bWVzL1JFQ0FTVC9kYXRhL291dHB1dHMvY2hpbGUvbW92ZW1lbnRzLzIwMjJfMDNfbW92LnJkcyIpICU+JSAKICBtdXRhdGUoR0VPTUVUUlkgPSBOVUxMKSAlPiUgCiAgZHBseXI6OmZpbHRlcihjb3VudHJ5ID09ICJDTCIpICU+JSAKICBzdF9hc19zZihjb29yZHMgPSBjKCJlbmRfbG9uIiwgImVuZF9sYXQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JzID0gJ0VQU0c6NDMyNicpCmBgYAoKIyMjIGJvdW5kYXJ5IGRhdGEKYGBge3J9CmFkbV9zaHAgPC0gc3RfcmVhZCgiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9kYXRhL21hcHMvc2hhcGVmaWxlcy9DaGlsZV9zaHAvYWRtL3Byb3ZpbmNlL1BST1ZJTkNJQVNfMjAyMC5zaHAiKSU+JSAKICBzdF9zaW1wbGlmeShwcmVzZXJ2ZVRvcG9sb2d5ID0gVCwKICAgICAgICAgICAgICBkVG9sZXJhbmNlID0gMTAwMCkgJT4lIAogIHN0X21ha2VfdmFsaWQoKSAlPiUgCiAgc3RfdHJhbnNmb3JtKGNycyA9ICdFUFNHOjQzMjYnKQoKYWRtMV9zaHAgPC0gc3RfcmVhZCgiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9kYXRhL21hcHMvc2hhcGVmaWxlcy9DaGlsZV9zaHAvYWRtL3JlZ2lvbi9SRUdJT05FU18yMDIwLnNocCIpJT4lIAogIHN0X3NpbXBsaWZ5KHByZXNlcnZlVG9wb2xvZ3kgPSBULAogICAgICAgICAgICAgIGRUb2xlcmFuY2UgPSAxMDAwKSAlPiUgCiAgc3RfbWFrZV92YWxpZCgpICU+JSAKICBzdF90cmFuc2Zvcm0oY3JzID0gJ0VQU0c6NDMyNicpCgpyZWdpb25fc2hwIDwtIHN0X3JlYWQoIi9Vc2Vycy9mcmFuY2lzY29yb3dlL0Ryb3Bib3gvRnJhbmNpc2NvL1Jlc2VhcmNoL2luX3Byb2dyZXNzL3JlY2FzdC9jZXBhbC1yZXBvcnQvZGF0YS9tYXBzL3NoYXBlZmlsZXMvQ2hpbGVfc2hwL2FkbS9jb3VudHJ5L2dhZG00MV9DSExfMC5zaHAiKSU+JSAKICBzdF9zaW1wbGlmeShwcmVzZXJ2ZVRvcG9sb2d5ID0gVCwKICAgICAgICAgICAgICBkVG9sZXJhbmNlID0gMTAwMCkgJT4lIAogIHN0X21ha2VfdmFsaWQoKSAlPiUgCiAgc3RfdHJhbnNmb3JtKGNycyA9ICdFUFNHOjQzMjYnKQpgYGAKCiMjIERhdGEgd3JhbmdsaW5nCmBgYHtyfQpkZjIwX291dCA8LSBkZjIwX2IgJT4lIAogIGZpbHRlcihzdGFydF9wb2x5Z29uX25hbWUgPT0gJ1NhbnRpYWdvJykKICAKZGYyMl9vdXQgPC0gZGYyMl9iICU+JSAKICBmaWx0ZXIoc3RhcnRfcG9seWdvbl9uYW1lID09ICdTYW50aWFnbycpCgpgYGAKCiMjIyBEZWZpbmUgZGlzdGFuY2UKYGBge3J9CmRmMjBfb3V0IDwtIGRmMjBfb3V0ICU+JSBtdXRhdGUoCiAgZGlzdGFuY2VfY2xhc3MgPSBjYXNlX3doZW4obGVuZ3RoX2ttIDwgMTAwIH4gIjwxMDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9rbSA+PSAxMDAgfiAiPjEwMCIpKQoKZGYyMl9vdXQgPC0gZGYyMl9vdXQgJT4lIG11dGF0ZSgKICBkaXN0YW5jZV9jbGFzcyA9IGNhc2Vfd2hlbihsZW5ndGhfa20gPCAxMDAgfiAiPDEwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2ttID49IDEwMCB+ICI+MTAwIikpCgpgYGAKCiMjIyBwcmVzZXJ2ZSBhIHVuaXF1ZSBnZW9tZXRyeQpgYGB7cn0KZGYyMF9vdXQgPC0gZGYyMF9vdXQgJT4lCiAgZ3JvdXBfYnkoZW5kX3BvbHlnb25fbmFtZSkgJT4lCiAgbXV0YXRlKGdlb21ldHJ5ID0gc3RfdW5pb24oZ2VvbWV0cnkpKSAlPiUKICB1bmdyb3VwKCkKCmRmMjJfb3V0IDwtIGRmMjJfb3V0ICU+JQogIGdyb3VwX2J5KGVuZF9wb2x5Z29uX25hbWUpICU+JQogIG11dGF0ZShnZW9tZXRyeSA9IHN0X3VuaW9uKGdlb21ldHJ5KSkgJT4lCiAgdW5ncm91cCgpCmBgYAoKIyMjIFN1bSBvZiBmbG93cwpgYGB7cn0Kb3V0Zmxvd3NfZGZfMjAgPC0gZGYyMF9vdXQgJT4lIAogIGZpbHRlcihzdGFydF9wb2x5Z29uX25hbWUgIT0gZW5kX3BvbHlnb25fbmFtZSkgJT4lIAogIGdyb3VwX2J5KHN0YXJ0X3BvbHlnb25fbmFtZSwgZW5kX3BvbHlnb25fbmFtZSwgZ2VvbWV0cnksIGRpc3RhbmNlX2NsYXNzKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZSgKICAgIHN1bV9vdXRmbG93ID0gc3VtKG5fY3Jpc2lzLCBuYS5ybSA9IFQpKSAlPiUgCiAgdW5ncm91cCgpIAoKb3V0Zmxvd3NfZGZfMjIgPC0gZGYyMl9vdXQgJT4lIAogIGZpbHRlcihzdGFydF9wb2x5Z29uX25hbWUgIT0gZW5kX3BvbHlnb25fbmFtZSkgJT4lIAogIGdyb3VwX2J5KHN0YXJ0X3BvbHlnb25fbmFtZSwgZW5kX3BvbHlnb25fbmFtZSwgZ2VvbWV0cnksIGRpc3RhbmNlX2NsYXNzKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZSgKICAgIHN1bV9vdXRmbG93ID0gc3VtKG5fY3Jpc2lzLCBuYS5ybSA9IFQpKSAlPiUgCiAgdW5ncm91cCgpIApgYGAKCiMjIyBDaGVjayBhbGlnbm1lbnQgYmV0d2VlbiBkYXRhIGZyYW1lcwpgYGB7cn0KcCA8LSBnZ3Bsb3QoKSArIAogIGdlb21fc2YoZGF0YSA9IGFkbV9zaHAsCiAgICAgICAgICBjb2xvciA9ICJncmF5NjAiLCAKICAgICAgICAgIHNpemUgPSAwLjEpIAoKbGFzdF9wbG90KCkKYGBgCgpgYGB7cn0KcCA8LSBwICsKICBnZW9tX3BvaW50KGRhdGEgPSBvdXRmbG93c19kZl8yMCwKICAgIGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwKICAgIHN0YXQgPSAic2ZfY29vcmRpbmF0ZXMiCiAgKSAKbGFzdF9wbG90KCkKYGBgCgojIyMgQWRkIHllYXIKYGBge3J9Cm91dGZsb3dzX2RmXzIwJHllYXIgPC0gJzIwMjAnCm91dGZsb3dzX2RmXzIyJHllYXIgPC0gJzIwMjInCmBgYAoKIyMjIEJpbmQgb3V0Zmxvd3MKYGBge3J9Cm91dGZsb3dzX2RmIDwtIHJiaW5kKG91dGZsb3dzX2RmXzIwLCBvdXRmbG93c19kZl8yMikKYGBgCgojIyMgSm9pbiBmbG93cyB0byBwb2x5Z29ucwpgYGB7cn0KbW9iX2luZGljYXRvcnNfMSA8LSBzdF9qb2luKGFkbV9zaHAsIG91dGZsb3dzX2RmKQpgYGAKCiMjIyBjbGFzc2lmeSBkYXRhIGludG8gcXVhbnRpbGVzCmBgYHtyfQptb2JfaW5kaWNhdG9yc18xJG5ld19qZW5rX2NsYXNzIDwtIGNsYXNzaWZ5X2ludGVydmFscyhtb2JfaW5kaWNhdG9yc18xJHN1bV9vdXRmbG93LCBuID0gNSwgc3R5bGUgPSAicXVhbnRpbGUiLCBmYWN0b3IgPSBUUlVFKQoKb3V0Zmxvd19sYWJlbHNfMSA8LSBsZXZlbHMobW9iX2luZGljYXRvcnNfMSRuZXdfamVua19jbGFzcykKb3V0Zmxvd19sYWJlbHNfMSA8LSBnc3ViKCJeLnwuJCIsICIiLCAgb3V0Zmxvd19sYWJlbHNfMSkKb3V0Zmxvd19sYWJlbHNfMSA8LSBnc3ViKCJcXC5bMC05XSsiLCAiIiwgIG91dGZsb3dfbGFiZWxzXzEpCm91dGZsb3dfbGFiZWxzXzEgPC0gZ3N1YigiXFwsIiwgIi0iLCAgb3V0Zmxvd19sYWJlbHNfMSkKbGV2ZWxzKG1vYl9pbmRpY2F0b3JzXzEkbmV3X2plbmtfY2xhc3MpIDwtIG91dGZsb3dfbGFiZWxzXzEKCiMgbW9iX2luZGljYXRvcnNfMSA8LSBtb2JfaW5kaWNhdG9yc18xICU+JSAKICAjIG11dGF0ZShuZXdfamVua19jbGFzcyA9IHN0cl9yZXBsYWNlKG5ld19qZW5rX2NsYXNzLCAiLCIsICItIikpCgojIGNoYW5nZSBnZW9tZXRyeQpzaHBfcmVnIDwtIHJlZ2lvbl9zaHAgJT4lIHN0X3RyYW5zZm9ybShjcnMgPSAnRVBTRzo0MzI2JykKYGBgCgpgYGB7cn0KbW9iX2luZGljYXRvcnNfMSRuZXdfamVua19jbGFzcyA8LSBtb2JfaW5kaWNhdG9yc18xJG5ld19qZW5rX2NsYXNzICU+JSByZXBsYWNlX25hKCIxMC00MjAiKQpgYGAKCmBgYHtyfQptb2JfaW5kaWNhdG9yc18xIDwtIG5hLm9taXQobW9iX2luZGljYXRvcnNfMSkKYGBgCgoKIyMgUGxvdHRpbmcKCiMjIyBDcm9wIGJvdW5kaW5nIGJveApgYGB7cn0KYmJveF9uZXcgPC0gc3RfYmJveChhZG1fc2hwKSAjIGN1cnJlbnQgYm91bmRpbmcgYm94Cgp4cmFuZ2UgPC0gYmJveF9uZXckeG1heCAtIGJib3hfbmV3JHhtaW4gIyByYW5nZSBvZiB4IHZhbHVlcwp5cmFuZ2UgPC0gYmJveF9uZXckeW1heCAtIGJib3hfbmV3JHltaW4gIyByYW5nZSBvZiB5IHZhbHVlcwoKYmJveF9uZXdbMV0gPC0gYmJveF9uZXdbMV0gKyAoMC42ICogeHJhbmdlKSAjIHhtaW4gLSBsZWZ0CgpiYm94X25ldyA8LSBiYm94X25ldyAlPiUgICMgdGFrZSB0aGUgYm91bmRpbmcgYm94IC4uLgogIHN0X2FzX3NmYygpICMgLi4uIGFuZCBtYWtlIGl0IGEgc2YgcG9seWdvbgoKZ2dwbG90KCkgKyAKICBnZW9tX3NmKGRhdGEgPSBhZG1fc2hwLAogICAgICAgICAgY29sb3IgPSAiZ3JheTYwIiwgCiAgICAgICAgICBzaXplID0gMC4xKSArCiAgZ2VvbV9wb2ludChkYXRhID0gb3V0Zmxvd3NfZGZfMjAsCiAgICBhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksCiAgICBzdGF0ID0gInNmX2Nvb3JkaW5hdGVzIiwKICAgIHNpemUgPSAuMQogICkgKwogIGNvb3JkX3NmKHhsaW0gPSBzdF9jb29yZGluYXRlcyhiYm94X25ldylbYygxLDIpLDFdLCAjIG1pbiAmIG1heCBvZiB4IHZhbHVlcwogICAgICAgICAgIHlsaW0gPSBzdF9jb29yZGluYXRlcyhiYm94X25ldylbYygyLDMpLDJdKSArICMgbWluICYgbWF4IG9mIHkgdmFsdWVzCiAgdGhlbWVfdm9pZCgpCmBgYAoKIyMjIENyZWF0aW5nIGluZGl2aWR1YWwgY291bnRyeSBtYXAKYGBge3J9CgpzaHBfcmVnJGNlbnRyb2lkIDwtIHNocF9yZWcgJT4lIAogIHN0X2NlbnRyb2lkKCkgJT4lIAogIHN0X2dlb21ldHJ5KCkKCnBhZGRpbmdfd2lkdGggPC0gMTcKcGFkZGluZ19oZWlnaHQgPC0gMjIKCmdncGxvdChkYXRhID0gbW9iX2luZGljYXRvcnNfMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhmaWxsID0gbmV3X2plbmtfY2xhc3MgKSkgKwogIGdlb21fc2YoY29sID0gInRyYW5zcGFyZW50Iiwgc2l6ZSA9IC4yKSArIAogIGNvb3JkX3NmKCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiT3JSZCIsIAogICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IDEsIAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjEwLTQyMSIsICI0MjItMTIzMSIsICIxLDIzMi0zLDM3MCIsICIzLDM3MS0yMiw3NjEiLCAiPiAyMiw3NjEiKSwKICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZT0iYmxhY2siKSArCiAgZmFjZXRfZ3JpZChkaXN0YW5jZV9jbGFzcyB+IHllYXIpICsKICBsYWJzKHRpdGxlID0gIkIuIENoaWxlIiwKICAgICAgIGZpbGwgPSAiTnVtYmVyIG9mIG91dC1tb3ZlcyIpICsKICB0aGVtZV9tYXAoKSArCiAgZ3VpZGVzKAogICAgY29sb3I9J25vbmUnLAogICAgZmlsbD1ndWlkZV9sZWdlbmQoCiAgICAgIGtleXdpZHRoID0gNCwKICAgICAga2V5aGVpZ2h0ID0gMSwKICAgICAgbnJvdyA9IDEsCiAgICAgIHRpdGxlLnBvc2l0aW9uPSJ0b3AiLAogICAgICBsYWJlbC5wb3NpdGlvbj0iYm90dG9tIgogICAgKQogICkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90Lm1hcmdpbj1tYXJnaW4oMSwwLDEsMCwiY20iKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X21hcmtkb3duKAogICAgICAgICAgc2l6ZT0xMCwgZmFjZSA9ICJib2xkIiwgaGp1c3Q9MC41LCBsaW5laGVpZ2h0PTAuNDUsCiAgICAgICAgICBjb2xvcj0iYmxhY2siLAogICAgICAgICAgbWFyZ2luPW1hcmdpbigwLDAsLTAuMiwwLCJjbSIpCiAgICAgICAgICApLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBsZWdlbmQuc3BhY2luZy54ID0gdW5pdCgwLCAnY20nKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTk5IiwgY29sb3VyID0gImdyYXk5OSIpCiAgICAgICAgKSArCiAgICBnZW9tX3NmKGRhdGEgPSByZWdpb25fc2hwLAogICAgICAgICAgY29sID0gImJsYWNrIiwgCiAgICAgICAgICBzaXplID0gMSwKICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiKSArCiAgICAgICAgICAgIGNvb3JkX3NmKHhsaW0gPSBjKHNocF9yZWckY2VudHJvaWRbWzFdXVsxXSAtIHBhZGRpbmdfd2lkdGgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaHBfcmVnJGNlbnRyb2lkW1sxXV1bMV0gKyBwYWRkaW5nX3dpZHRoKSwgCiAgICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKHNocF9yZWckY2VudHJvaWRbWzFdXVsyXSAtIHBhZGRpbmdfaGVpZ2h0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hwX3JlZyRjZW50cm9pZFtbMV1dWzJdICsgcGFkZGluZ19oZWlnaHQpLCAKICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBGQUxTRSkKCm91dGZsb3dfcGxvdF9jaGkgPC0gbGFzdF9wbG90KCkKYGBgCiMjIyBTYXZpbmcgY291bnRyeSBtYXAKYGBge3J9CnBuZygiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9vdXRwdXRzL2Nsb3JvcGxldGgtbWFwcy9jaGlsZS9jbG9yb3BsZXRoLWNoaS5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHJlcz0zMDApCiAgbGFzdF9wbG90KCkKZGV2Lm9mZigpCmBgYAoKIyMjIENyZWF0ZSBtYXAgZm9yIFNhbnRpYWdvCgpTaG9ydC1kaXN0YW5jZQpgYGB7cn0KbWV0cm9fcmVnaW9uX3NocCA8LSBhZG0xX3NocCAlPiUgZmlsdGVyKFJFR0lPTiA9PSAiTWV0cm9wb2xpdGFuYSBkZSBTYW50aWFnbyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJFR0lPTiA9PSAiVmFscGFyYcOtc28iIHwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUkVHSU9OID09ICJMaWJlcnRhZG9yIEdlbmVyYWwgQmVybmFyZG8gTydIaWdnaW5zIikKCm1ldHJvX3JlZ2lvbl9zaHAkY2VudHJvaWQgPC0gbWV0cm9fcmVnaW9uX3NocCAgJT4lIAogIHN0X2NlbnRyb2lkKCkgJT4lIAogIHN0X2dlb21ldHJ5KCkKCnBhZGRpbmdfd2lkdGggPC0gMgpwYWRkaW5nX2hlaWdodCA8LSAxLjgKCmNvbF9wYWwgPC0gYygjIiNmZWYwZDkiLAogICAgICAgICAgICAgIyIjZmRjYzhhIiwKICAgICAgICAgICAgICIjZmM4ZDU5IiwKICAgICAgICAgICAgICIjZTM0YTMzIiwKICAgICAgICAgICAgICIjYjMwMDAwIikKCiMgMjAyMAptb2JfaW5kaWNhdG9yc18xICU+JSBmaWx0ZXIoUkVHSU9OID09ICJNZXRyb3BvbGl0YW5hIGRlIFNhbnRpYWdvIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUkVHSU9OID09ICJWYWxwYXJhw61zbyIgfCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSRUdJT04gPT0gIkxpYmVydGFkb3IgR2VuZXJhbCBCZXJuYXJkbyBPJ0hpZ2dpbnMiKSAlPiUgCiAgZmlsdGVyKHllYXIgPT0gIjIwMjAiKSAlPiUgCiAgZmlsdGVyKGRpc3RhbmNlX2NsYXNzID09ICI8MTAwIikgJT4lIAogICBnZ3Bsb3QoYWVzKGZpbGwgPSBuZXdfamVua19jbGFzcykpICsKICAgICBnZW9tX3NmKGNvbCA9ICJ3aGl0ZSIsIHNpemUgPSAuMSkgKwogICBjb29yZF9zZigpICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xfcGFsKSArCiAgIyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIk9yUmQiLCAKICAjICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IDEsIAogICMgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMTAtNDIxIiwgIjQyMi0xMjMxIiwgIjEsMjMyLTMsMzcwIiwgIjMsMzcxLTIyLDc2MSIsICI+IDIyLDc2MSIpKSArCiAgIHRoZW1lX21hcCgpICsKICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNjApLAogICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGNvbG91cj0iYmxhY2siKQogICAgICAgICApICsKICAgbGFicyh0aXRsZSA9ICJTYW50aWFnbyIpICsKICAgIGdlb21fc2YoZGF0YSA9IG1ldHJvX3JlZ2lvbl9zaHAsCiAgICAgICAgICBjb2wgPSAiYmxhY2siLCAKICAgICAgICAgIHNpemUgPSAxLAogICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiKSArCiAgICAgICAgICAgIGNvb3JkX3NmKHhsaW0gPSBjKG1ldHJvX3JlZ2lvbl9zaHAkY2VudHJvaWRbWzNdXVsxXSAtIHBhZGRpbmdfd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJvX3JlZ2lvbl9zaHAkY2VudHJvaWRbWzNdXVsxXSArIHBhZGRpbmdfd2lkdGggLSAuNSksCiAgICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKG1ldHJvX3JlZ2lvbl9zaHAkY2VudHJvaWRbWzNdXVsyXSAtIHBhZGRpbmdfaGVpZ2h0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRyb19yZWdpb25fc2hwJGNlbnRyb2lkW1szXV1bMl0gKyBwYWRkaW5nX2hlaWdodCksCiAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gRkFMU0UpCgpzZ3RvX21hcDIwMjAgPC0gbGFzdF9wbG90KCkKYGBgCgoKYGBge3J9CiMgMjAyMgoKY29sX3BhbCA8LSBjKCMiI2ZlZjBkOSIsCiAgICAgICAgICAgICAjIiNmZGNjOGEiLAogICAgICAgICAgICAgIyIjZmM4ZDU5IiwKICAgICAgICAgICAgICIjZTM0YTMzIiwKICAgICAgICAgICAgICIjYjMwMDAwIgogICAgICAgICAgICAgKQoKbW9iX2luZGljYXRvcnNfMSAlPiUgZmlsdGVyKFJFR0lPTiA9PSAiTWV0cm9wb2xpdGFuYSBkZSBTYW50aWFnbyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJFR0lPTiA9PSAiVmFscGFyYcOtc28iIHwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUkVHSU9OID09ICJMaWJlcnRhZG9yIEdlbmVyYWwgQmVybmFyZG8gTydIaWdnaW5zIikgJT4lIAogIGZpbHRlcih5ZWFyID09ICIyMDIyIikgJT4lIAogIGZpbHRlcihkaXN0YW5jZV9jbGFzcyA9PSAiPDEwMCIpICU+JSAKICAgZ2dwbG90KGFlcyhmaWxsID0gbmV3X2plbmtfY2xhc3MpKSArCiAgICAgZ2VvbV9zZihjb2wgPSAid2hpdGUiLCBzaXplID0gLjEpICsKICAgY29vcmRfc2YoKSArCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sX3BhbCkgKwogICMgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJPclJkIiwgCiAgIyAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAxLCAKICAjICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjEwLTQyMSIsICI0MjItMTIzMSIsICIxLDIzMi0zLDM3MCIsICIzLDM3MS0yMiw3NjEiLCAiPiAyMiw3NjEiKSkgKwogICB0aGVtZV9tYXAoKSArCiAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYwKSwKICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kPWVsZW1lbnRfcmVjdChjb2xvdXI9ImJsYWNrIikKICAgICAgICAgKSArCiAgIGxhYnModGl0bGUgPSAiU2FudGlhZ28iKSArCiAgICBnZW9tX3NmKGRhdGEgPSBtZXRyb19yZWdpb25fc2hwLAogICAgICAgICAgY29sID0gImJsYWNrIiwgCiAgICAgICAgICBzaXplID0gMSwKICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IikgKwogICAgICAgICAgICBjb29yZF9zZih4bGltID0gYyhtZXRyb19yZWdpb25fc2hwJGNlbnRyb2lkW1szXV1bMV0gLSBwYWRkaW5nX3dpZHRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRyb19yZWdpb25fc2hwJGNlbnRyb2lkW1szXV1bMV0gKyBwYWRkaW5nX3dpZHRoIC0gLjUpLAogICAgICAgICAgICAgICAgICAgICB5bGltID0gYyhtZXRyb19yZWdpb25fc2hwJGNlbnRyb2lkW1szXV1bMl0gLSBwYWRkaW5nX2hlaWdodCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0cm9fcmVnaW9uX3NocCRjZW50cm9pZFtbM11dWzJdICsgcGFkZGluZ19oZWlnaHQpLAogICAgICAgICAgICAgICAgICAgIGV4cGFuZCA9IEZBTFNFKQoKc2d0b19tYXAyMDIyIDwtIGxhc3RfcGxvdCgpCgpgYGAKCmBgYHtyfQpwbmcoIi9Vc2Vycy9mcmFuY2lzY29yb3dlL0Ryb3Bib3gvRnJhbmNpc2NvL1Jlc2VhcmNoL2luX3Byb2dyZXNzL3JlY2FzdC9jZXBhbC1yZXBvcnQvb3V0cHV0cy9jbG9yb3BsZXRoLW1hcHMvY2hpbGUvY2xvcm9wbGV0aC1zZ3RvMjAyMC5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHJlcz0zMDApCiAgc2d0b19tYXAyMDIwCmRldi5vZmYoKQoKcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL2NoaWxlL2Nsb3JvcGxldGgtc2d0bzIwMjIucG5nIiwgdW5pdHM9ImluIiwgd2lkdGg9OCwgaGVpZ2h0PTEwLCByZXM9MzAwKQogIHNndG9fbWFwMjAyMgpkZXYub2ZmKCkKYGBgCgojIyMgQ3JlYXRlIGJhciBwbG90CgojIyMjIFNob3J0LWRpc3RhbmNlCmBgYHtyfQpjb2xfcGFsIDwtIGMoIyIjZmVmMGQ5IiwKICAgICAgICAgICAgICMiI2ZkY2M4YSIsCiAgICAgICAgICAgICAiI2ZjOGQ1OSIsCiAgICAgICAgICAgICAiI2UzNGEzMyIsCiAgICAgICAgICAgICAiI2IzMDAwMCIKICAgICAgICAgICAgICkKCm1vYl9pbmRpY2F0b3JzXzEkZW5kX3BvbHlnb25fbmFtZVttb2JfaW5kaWNhdG9yc18xJGVuZF9wb2x5Z29uX25hbWUgPT0gIlNhbiBGZWxpcGUgZGUgQWNvbmNhZ3VhIl0gPC0gIlNhbiBGZWxpcGUiCgojIDIwMjAKbW9iX2luZGljYXRvcnNfMSAlPiUgZmlsdGVyKHllYXIgPT0gIjIwMjAiKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2VfY2xhc3MgPT0gIjwxMDAiKSAlPiUgCiAgYXJyYW5nZShkZXNjKHN1bV9vdXRmbG93KSkgJT4lIAogICAgbXV0YXRlKG91dGZsb3dfdG90YWwgPSBzdW0oc3VtX291dGZsb3cpLAogICAgICAgICBvdXRmbG93X3BlcmNlbnQgPSByb3VuZCggKHN1bV9vdXRmbG93L291dGZsb3dfdG90YWwpKjEwMCwgMiApICkgJT4lIAogIGhlYWQobiA9IDEwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihlbmRfcG9seWdvbl9uYW1lLCBvdXRmbG93X3BlcmNlbnQpLCB5ID0gb3V0Zmxvd19wZXJjZW50LCBmaWxsID0gbmV3X2plbmtfY2xhc3MpKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiApICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xfcGFsKSArCiAgdGhlbWVfdHVmdGUyKCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZSA9ICJUb3AgdGVuIG91dGZsb3dzIiwKICAgICAgIHkgPSAiUGVyY2VudCAoJSkiKSArCiAgdGhlbWUocGxvdC5tYXJnaW49bWFyZ2luKDEsMCwxLDEsImNtIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDM1KSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAjIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkpICMgU2V0IGN1c3RvbSB5LWF4aXMgbGFiZWxzCgpiYXJwX3Nob3J0MjAyMCA8LSBsYXN0X3Bsb3QoKQpgYGAKCmBgYHtyfQpjb2xfcGFsIDwtIGMoIyIjZmVmMGQ5IiwKICAgICAgICAgICAgICMiI2ZkY2M4YSIsCiAgICAgICAgICAgICAjIiNmYzhkNTkiLAogICAgICAgICAgICAgIiNlMzRhMzMiLAogICAgICAgICAgICAgIiNiMzAwMDAiCiAgICAgICAgICAgICApCiMgMjAyMgptb2JfaW5kaWNhdG9yc18xICU+JSBmaWx0ZXIoeWVhciA9PSAiMjAyMiIpICU+JQogIGZpbHRlcihkaXN0YW5jZV9jbGFzcyA9PSAiPDEwMCIpICU+JSAKICBhcnJhbmdlKGRlc2Moc3VtX291dGZsb3cpKSAlPiUgCiAgICBtdXRhdGUob3V0Zmxvd190b3RhbCA9IHN1bShzdW1fb3V0ZmxvdyksCiAgICAgICAgIG91dGZsb3dfcGVyY2VudCA9IHJvdW5kKCAoc3VtX291dGZsb3cvb3V0Zmxvd190b3RhbCkqMTAwLCAyICkgKSAlPiUgCiAgZGlzdGluY3QoZW5kX3BvbHlnb25fbmFtZSwgLmtlZXBfYWxsPVRSVUUpICU+JSAKICBoZWFkKG4gPSAxMCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoZW5kX3BvbHlnb25fbmFtZSwgb3V0Zmxvd19wZXJjZW50KSwgeSA9IG91dGZsb3dfcGVyY2VudCwgZmlsbCA9IG5ld19qZW5rX2NsYXNzKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIgKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sX3BhbCkgKwogIHRoZW1lX3R1ZnRlMigpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiVG9wIHRlbiBvdXRmbG93cyIsCiAgICAgICB5ID0gIlBlcmNlbnQgKCUpIikgKwogIHRoZW1lKHBsb3QubWFyZ2luPW1hcmdpbigxLDAsMSwxLCJjbSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzNSksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICNheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpKSAjIFNldCBjdXN0b20geS1heGlzIGxhYmVscwoKYmFycF9zaG9ydDIwMjIgPC0gbGFzdF9wbG90KCkKYGBgCgpgYGB7cn0KcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL2NoaWxlL2JhcnBfc2hvcnQyMDIwLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBiYXJwX3Nob3J0MjAyMApkZXYub2ZmKCkKCnBuZygiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9vdXRwdXRzL2Nsb3JvcGxldGgtbWFwcy9jaGlsZS9iYXJwX3Nob3J0MjAyMi5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHJlcz0zMDApCiAgYmFycF9zaG9ydDIwMjIKZGV2Lm9mZigpCmBgYAoKIyMjIyBMb25nLWRpc3RhbmNlCmBgYHtyfQpjb2xfcGFsIDwtIGMoIiNmZWYwZDkiLAogICAgICAgICAgICAgIiNmZGNjOGEiLAogICAgICAgICAgICAgIiNmYzhkNTkiCiAgICAgICAgICAgICAjIiNlMzRhMzMiLAogICAgICAgICAgICAgIyIjYjMwMDAwIgogICAgICAgICAgICAgKQoKIyAyMDIwCm1vYl9pbmRpY2F0b3JzXzEgJT4lIGZpbHRlcih5ZWFyID09ICIyMDIwIikgJT4lCiAgZmlsdGVyKGRpc3RhbmNlX2NsYXNzID09ICI+MTAwIikgJT4lIAogIGFycmFuZ2UoZGVzYyhzdW1fb3V0ZmxvdykpICU+JSAKICAgIG11dGF0ZShvdXRmbG93X3RvdGFsID0gc3VtKHN1bV9vdXRmbG93KSwKICAgICAgICAgb3V0Zmxvd19wZXJjZW50ID0gcm91bmQoIChzdW1fb3V0Zmxvdy9vdXRmbG93X3RvdGFsKSoxMDAsIDIgKSApICU+JSAKICBkaXN0aW5jdChlbmRfcG9seWdvbl9uYW1lLCAua2VlcF9hbGw9VFJVRSkgJT4lIAogIGhlYWQobiA9IDEwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihlbmRfcG9seWdvbl9uYW1lLCBvdXRmbG93X3BlcmNlbnQpLCB5ID0gb3V0Zmxvd19wZXJjZW50LCBmaWxsID0gbmV3X2plbmtfY2xhc3MpKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiApICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xfcGFsKSArCiAgdGhlbWVfdHVmdGUyKCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZSA9ICJUb3AgdGVuIG91dGZsb3dzIiwKICAgICAgIHkgPSAiUGVyY2VudCAoJSkiKSArCiAgdGhlbWUocGxvdC5tYXJnaW49bWFyZ2luKDEsMCwxLDEsImNtIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDM1KSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAjIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCkpICMgU2V0IGN1c3RvbSB5LWF4aXMgbGFiZWxzCgpiYXJwX2xvbmcyMDIwIDwtIGxhc3RfcGxvdCgpCmBgYAoKCmBgYHtyfQojIDIwMjIKCmNvbF9wYWwgPC0gYygjIiNmZWYwZDkiLAogICAgICAgICAgICAgIyIjZmRjYzhhIiwKICAgICAgICAgICAgICIjZmM4ZDU5IiwKICAgICAgICAgICAgICIjZTM0YTMzIgogICAgICAgICAgICAgIyIjYjMwMDAwIgogICAgICAgICAgICAgKQoKbW9iX2luZGljYXRvcnNfMSAlPiUgZmlsdGVyKHllYXIgPT0gIjIwMjIiKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2VfY2xhc3MgPT0gIj4xMDAiKSAlPiUgCiAgYXJyYW5nZShkZXNjKHN1bV9vdXRmbG93KSkgJT4lIAogICAgbXV0YXRlKG91dGZsb3dfdG90YWwgPSBzdW0oc3VtX291dGZsb3cpLAogICAgICAgICBvdXRmbG93X3BlcmNlbnQgPSByb3VuZCggKHN1bV9vdXRmbG93L291dGZsb3dfdG90YWwpKjEwMCwgMiApICkgJT4lIAogIGRpc3RpbmN0KGVuZF9wb2x5Z29uX25hbWUsIC5rZWVwX2FsbD1UUlVFKSAlPiUgCiAgaGVhZChuID0gMTApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGVuZF9wb2x5Z29uX25hbWUsIG91dGZsb3dfcGVyY2VudCksIHkgPSBvdXRmbG93X3BlcmNlbnQsIGZpbGwgPSBuZXdfamVua19jbGFzcykpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiICkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGNvbF9wYWwpICsKICB0aGVtZV90dWZ0ZTIoKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlRvcCB0ZW4gb3V0Zmxvd3MiLAogICAgICAgeSA9ICJQZXJjZW50ICglKSIpICsKICB0aGVtZShwbG90Lm1hcmdpbj1tYXJnaW4oMSwwLDEsMSwiY20iKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzUpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICMgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgIyBTZXQgY3VzdG9tIHktYXhpcyBsYWJlbHMKCmJhcnBfbG9uZzIwMjIgPC0gbGFzdF9wbG90KCkKYGBgCmBgYHtyfQpwbmcoIi9Vc2Vycy9mcmFuY2lzY29yb3dlL0Ryb3Bib3gvRnJhbmNpc2NvL1Jlc2VhcmNoL2luX3Byb2dyZXNzL3JlY2FzdC9jZXBhbC1yZXBvcnQvb3V0cHV0cy9jbG9yb3BsZXRoLW1hcHMvY2hpbGUvYmFycF9sb25nMjAyMC5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHJlcz0zMDApCiAgYmFycF9sb25nMjAyMApkZXYub2ZmKCkKCnBuZygiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9vdXRwdXRzL2Nsb3JvcGxldGgtbWFwcy9jaGlsZS9iYXJwX2xvbmcyMDIyLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBiYXJwX2xvbmcyMDIyCmRldi5vZmYoKQpgYGAKCgojIE1leGljbwoKIyMjIG1vYmlsaXR5IGRhdGEKYGBge3J9CiMgMjAyMCBvdXQKZGYyMF9vdXQgPC0gcmVhZFJEUygiL1ZvbHVtZXMvUkVDQVNUL2RhdGEvb3V0cHV0cy9tZXhpY28vbW92ZW1lbnRzLzIwMjBfMDRfbW92LnJkcyIpICU+JSAKICBtdXRhdGUoR0VPTUVUUlkgPSBOVUxMKSAlPiUgCiAgZHBseXI6OmZpbHRlcihjb3VudHJ5ID09ICJNWCIpICU+JSAKICBzdF9hc19zZihjb29yZHMgPSBjKCJlbmRfbG9uIiwgImVuZF9sYXQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JzID0gJ0VQU0c6NDMyNicpCgojIDIwMjIgb3V0CmRmMjJfb3V0IDwtIHJlYWRSRFMoIi9Wb2x1bWVzL1JFQ0FTVC9kYXRhL291dHB1dHMvbWV4aWNvL21vdmVtZW50cy8yMDIyXzAzX21vdi5yZHMiKSAlPiUgCiAgbXV0YXRlKEdFT01FVFJZID0gTlVMTCkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoY291bnRyeSA9PSAiTVgiKSAlPiUgCiAgc3RfYXNfc2YoY29vcmRzID0gYygiZW5kX2xvbiIsICJlbmRfbGF0IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNycyA9ICdFUFNHOjQzMjYnKQpgYGAKCiMjIyBib3VuZGFyeSBkYXRhCmBgYHtyfQojIGFkbWluIGJvdW5kYXJpZXMgc2hhcGUKYWRtX3NocCA8LSBzdF9yZWFkKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L2RhdGEvbWFwcy9zaGFwZWZpbGVzL2dhZG00MV9NRVhfc2hwL2dhZG00MV9NRVhfMi5zaHAiKSU+JSAKICBzdF9zaW1wbGlmeShwcmVzZXJ2ZVRvcG9sb2d5ID0gVCwKICAgICAgICAgICAgICBkVG9sZXJhbmNlID0gMTAwMCkgJT4lIAogIHN0X21ha2VfdmFsaWQoKSAlPiUgCiAgc3RfdHJhbnNmb3JtKGNycyA9ICdFUFNHOjQzMjYnKQoKYWRtMV9zaHAgPC0gc3RfcmVhZCgiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9kYXRhL21hcHMvc2hhcGVmaWxlcy9nYWRtNDFfTUVYX3NocC9nYWRtNDFfTUVYXzEuc2hwIiklPiUgCiAgc3Rfc2ltcGxpZnkocHJlc2VydmVUb3BvbG9neSA9IFQsCiAgICAgICAgICAgICAgZFRvbGVyYW5jZSA9IDEwMDApICU+JSAKICBzdF9tYWtlX3ZhbGlkKCkgJT4lIAogIHN0X3RyYW5zZm9ybShjcnMgPSAnRVBTRzo0MzI2JykKCiMgcmVnaW9uIHNoYXBlCnJlZ2lvbl9zaHAgPC0gc3RfcmVhZCgiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9kYXRhL21hcHMvc2hhcGVmaWxlcy9nYWRtNDFfTUVYX3NocC9nYWRtNDFfTUVYXzAuc2hwIiklPiUgCiAgc3Rfc2ltcGxpZnkocHJlc2VydmVUb3BvbG9neSA9IFQsCiAgICAgICAgICAgICAgZFRvbGVyYW5jZSA9IDEwMDApICU+JSAKICBzdF9tYWtlX3ZhbGlkKCkgJT4lIAogIHN0X3RyYW5zZm9ybShjcnMgPSAnRVBTRzo0MzI2JykKYGBgCiMjIERhdGEgd3JhbmdsaW5nCmBgYHtyfQojIGZpbHRlciBmb3Igc3RhcnQgbG9jYXRpb24gYXMgbWV4aWNvIGNpdHkKZGYyMF9vdXQgPC0gZGYyMF9vdXQgJT4lCiAgZmlsdGVyKHN0YXJ0X3BvbHlnb25fbmFtZSA9PSAnQ2l1ZGFkIERlIE3DqXhpY28nKQoKZGYyMl9vdXQgPC0gZGYyMl9vdXQgJT4lCiAgZmlsdGVyKHN0YXJ0X3BvbHlnb25fbmFtZSA9PSAnQ2l1ZGFkIERlIE3DqXhpY28nKQoKYGBgCgojIyMgRGVmaW5lIGRpc3RhbmNlCmBgYHtyfQpkZjIwX291dCA8LSBkZjIwX291dCAlPiUgbXV0YXRlKAogIGRpc3RhbmNlX2NsYXNzID0gY2FzZV93aGVuKGxlbmd0aF9rbSA8IDEwMCB+ICI8MTAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhfa20gPj0gMTAwIH4gIj4xMDAiKSkKCmRmMjJfb3V0IDwtIGRmMjJfb3V0ICU+JSBtdXRhdGUoCiAgZGlzdGFuY2VfY2xhc3MgPSBjYXNlX3doZW4obGVuZ3RoX2ttIDwgMTAwIH4gIjwxMDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9rbSA+PSAxMDAgfiAiPjEwMCIpKQoKYGBgCgojIyMgU3VtIG9mIGZsb3dzCmBgYHtyfQojIHN1bSBvZiBvdXRmbG93cwpvdXRmbG93c19kZl8yMCA8LSBkZjIwX291dCAlPiUgCiAgZmlsdGVyKHN0YXJ0X3BvbHlnb25fbmFtZSAhPSBlbmRfcG9seWdvbl9uYW1lKSAlPiUgCiAgZ3JvdXBfYnkoZ2VvbWV0cnksIGRpc3RhbmNlX2NsYXNzKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZSgKICAgIHN1bV9vdXRmbG93ID0gc3VtKG5fY3Jpc2lzLCBuYS5ybSA9IFQpKSAlPiUgCiAgdW5ncm91cCgpIAoKb3V0Zmxvd3NfZGZfMjIgPC0gZGYyMl9vdXQgJT4lIAogIGZpbHRlcihzdGFydF9wb2x5Z29uX25hbWUgIT0gZW5kX3BvbHlnb25fbmFtZSkgJT4lIAogIGdyb3VwX2J5KGdlb21ldHJ5LCBkaXN0YW5jZV9jbGFzcykgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoCiAgICBzdW1fb3V0ZmxvdyA9IHN1bShuX2NyaXNpcywgbmEucm0gPSBUKSkgJT4lIAogIHVuZ3JvdXAoKSAKCmBgYAojIyMgQ2hlY2sgYWxpZ25tZW50IGJldHdlZW4gZGF0YSBmcmFtZXMKYGBge3J9CiMgcGxvdCBib3VuZGFyaWVzIC0gdGVzdCAKcCA8LSBnZ3Bsb3QoKSArIAogIGdlb21fc2YoZGF0YSA9IGFkbV9zaHAsCiAgICAgICAgICBjb2xvciA9ICJncmF5NjAiLCAKICAgICAgICAgIHNpemUgPSAwLjEpIAoKbGFzdF9wbG90KCkKYGBgCgpgYGB7cn0KIyBjaGVjayBnZW9tZXRyeSBmaXRzIGludG8gZWl0aGVyIGFkbWluIGJvdW5kYXJpZXMgb3IgcmVnaW9uIGJvdW5kYXJpZXMKcCA8LSBwICsKICBnZW9tX3BvaW50KGRhdGEgPSBvdXRmbG93c19kZl8yMCwKICAgIGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwKICAgIHN0YXQgPSAic2ZfY29vcmRpbmF0ZXMiCiAgKSAKbGFzdF9wbG90KCkKYGBgCiMjIyBBZGQgeWVhcgpgYGB7cn0KIyBhc3NpZ24gYSB5ZWFyIHRvIGVhY2gKb3V0Zmxvd3NfZGZfMjAkeWVhciA8LSAnMjAyMCcKb3V0Zmxvd3NfZGZfMjIkeWVhciA8LSAnMjAyMicKYGBgCgojIyMgQmluZCBvdXRmbG93cwpgYGB7cn0Kb3V0Zmxvd3NfZGYgPC0gcmJpbmQob3V0Zmxvd3NfZGZfMjAsIG91dGZsb3dzX2RmXzIyKQpgYGAKCiMjIyBKb2luIGZsb3dzIHRvIHBvbHlnb25zCmBgYHtyfQptb2JfaW5kaWNhdG9yc18xIDwtIHN0X2pvaW4oYWRtX3NocCwgb3V0Zmxvd3NfZGYpCmBgYAoKIyMjIGNsYXNzaWZ5IGRhdGEgaW50byBxdWFudGlsZXMKYGBge3J9Cm1vYl9pbmRpY2F0b3JzXzEkbmV3X2plbmtfY2xhc3MgPC0gY2xhc3NpZnlfaW50ZXJ2YWxzKG1vYl9pbmRpY2F0b3JzXzEkc3VtX291dGZsb3csIG4gPSA1LCBzdHlsZSA9ICJxdWFudGlsZSIsIGZhY3RvciA9IFRSVUUpCgpvdXRmbG93X2xhYmVsc18xIDwtIGxldmVscyhtb2JfaW5kaWNhdG9yc18xJG5ld19qZW5rX2NsYXNzKQpvdXRmbG93X2xhYmVsc18xIDwtIGdzdWIoIl4ufC4kIiwgIiIsICBvdXRmbG93X2xhYmVsc18xKQpvdXRmbG93X2xhYmVsc18xIDwtIGdzdWIoIlxcLlswLTldKyIsICIiLCAgb3V0Zmxvd19sYWJlbHNfMSkKb3V0Zmxvd19sYWJlbHNfMSA8LSBnc3ViKCJcXCwiLCAiLSIsICBvdXRmbG93X2xhYmVsc18xKQpsZXZlbHMobW9iX2luZGljYXRvcnNfMSRuZXdfamVua19jbGFzcykgPC0gb3V0Zmxvd19sYWJlbHNfMQoKIyBtb2JfaW5kaWNhdG9yc18xIDwtIG1vYl9pbmRpY2F0b3JzXzEgJT4lIAogICMgbXV0YXRlKG5ld19qZW5rX2NsYXNzID0gc3RyX3JlcGxhY2UobmV3X2plbmtfY2xhc3MsICIsIiwgIi0iKSkKCiMgY2hhbmdlIGdlb21ldHJ5CnNocF9yZWcgPC0gcmVnaW9uX3NocCAlPiUgc3RfdHJhbnNmb3JtKGNycyA9ICdFUFNHOjQzMjYnKQpgYGAKYGBge3J9Cm1vYl9pbmRpY2F0b3JzXzEkbmV3X2plbmtfY2xhc3MgPC0gbW9iX2luZGljYXRvcnNfMSRuZXdfamVua19jbGFzcyAlPiUgcmVwbGFjZV9uYSgiMTAtOTIiKQpgYGAKCmBgYHtyfQptb2JfaW5kaWNhdG9yc18xIDwtIG5hLm9taXQobW9iX2luZGljYXRvcnNfMSkKYGBgCgoKIyMgUGxvdHRpbmcKCiMjIyBDcmVhdGluZyBpbmRpdmlkdWFsIGNvdW50cnkgbWFwCmBgYHtyfQoKc2hwX3JlZyRjZW50cm9pZCA8LSBzaHBfcmVnICU+JSAKICBzdF9jZW50cm9pZCgpICU+JSAKICBzdF9nZW9tZXRyeSgpCgpwYWRkaW5nX3dpZHRoIDwtIDE3IApwYWRkaW5nX2hlaWdodCA8LSAyMgoKbmV3X3lfbGFiZWxzIDwtIGMoIlNob3J0LWRpc3RhbmNlICg8MTAwa20pIiwgIkxvbmctZGlzdGFuY2UgKD4xMDBrbSkiKQpuYW1lcyhuZXdfeV9sYWJlbHMpIDwtIGMoIjwxMDAiLCAiPjEwMCIpCgpnZ3Bsb3QoZGF0YSA9IG1vYl9pbmRpY2F0b3JzXzEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoZmlsbCA9IG5ld19qZW5rX2NsYXNzICkpICsKICBnZW9tX3NmKGNvbCA9ICJ0cmFuc3BhcmVudCIsIHNpemUgPSAuMSkgKyAKICBjb29yZF9zZigpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIk9yUmQiLCAKICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAxLCAKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIxMC05MiIsICI5My00NDMiLCAiNDQ0LTEsNjU0IiwgIjEsNjU1LTQsNDU4IiwgIj4gNCw0NTgiKSwgCiAgICAgICAgICAgICAgICAgICAgbmEudmFsdWU9ImJsYWNrIikgKwogIGZhY2V0X2dyaWQoZGlzdGFuY2VfY2xhc3MgfiB5ZWFyLCAKICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIoZGlzdGFuY2VfY2xhc3MgPSBuZXdfeV9sYWJlbHMpKSArCiAgbGFicyh0aXRsZSA9ICJDLiBNZXhpY28iLAogICAgICAgZmlsbCA9ICJOdW1iZXIgb2Ygb3V0LW1vdmVzIikgKwogIHRoZW1lX21hcCgpICsKICBndWlkZXMoCiAgICBjb2xvcj0nbm9uZScsCiAgICBmaWxsID0gZ3VpZGVfbGVnZW5kKAogICAgICBrZXl3aWR0aCA9IDQsIAogICAgICBrZXloZWlnaHQgPSAxLAogICAgICBucm93ID0gMSwKICAgICAgdGl0bGUucG9zaXRpb249InRvcCIsCiAgICAgIGxhYmVsLnBvc2l0aW9uPSJib3R0b20iCiAgICApCiAgKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDEsMCwxLDAsImNtIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9tYXJrZG93bigKICAgICAgICAgIHNpemU9MTAsIAogICAgICAgICAgZmFjZSA9ICJib2xkIiwgCiAgICAgICAgICBoanVzdD0wLjUsIAogICAgICAgICAgbGluZWhlaWdodD0wLjQ1LAogICAgICAgICAgY29sb3I9ImJsYWNrIiwKICAgICAgICAgIG1hcmdpbj1tYXJnaW4oMCwwLC0wLjIsMCwiY20iKQogICAgICAgICAgKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoMCwgJ2NtJyksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXk5OSIsIGNvbG91ciA9ICJncmF5OTkiKQogICAgICAgICkgKwogICAgZ2VvbV9zZihkYXRhID0gc2hwX3JlZywKICAgICAgICAgIGNvbCA9ICJibGFjayIsIAogICAgICAgICAgc2l6ZSA9IDEsCiAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IikgKwogICAgICAgICAgICBjb29yZF9zZih4bGltID0gYyhzaHBfcmVnJGNlbnRyb2lkW1sxXV1bMV0gLSBwYWRkaW5nX3dpZHRoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hwX3JlZyRjZW50cm9pZFtbMV1dWzFdICsgcGFkZGluZ193aWR0aCksIAogICAgICAgICAgICAgICAgICAgICB5bGltID0gYyhzaHBfcmVnJGNlbnRyb2lkW1sxXV1bMl0gLSBwYWRkaW5nX2hlaWdodCAtIDcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaHBfcmVnJGNlbnRyb2lkW1sxXV1bMl0gKyBwYWRkaW5nX2hlaWdodCAtIDIpLCAKICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBGQUxTRSkKCm91dGZsb3dfcGxvdF9tZXggPC0gbGFzdF9wbG90KCkKCmBgYAoKIyMjIFNhdmluZyBjb3VudHJ5IG1hcApgYGB7cn0KcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL21leGljby9jbG9yb3BsZXRoLW1leDEucG5nIiwgdW5pdHM9ImluIiwgd2lkdGg9OCwgaGVpZ2h0PTEwLCByZXM9MzAwKQogIG91dGZsb3dfcGxvdF9tZXgKZGV2Lm9mZigpCmBgYAoKCiMjIyBDcmVhdGUgbWFwIGZvciBNZXhpY28gQ2l0eQoKU2hvcnQtZGlzdGFuY2UKYGBge3J9Cm14Y2l0eV9yZWdpb25fc2hwIDwtIGFkbTFfc2hwICU+JSBmaWx0ZXIoTkFNRV8xID09ICJEaXN0cml0byBGZWRlcmFsIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQU1FXzEgPT0gIk3DqXhpY28iIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BTUVfMSA9PSAiSGlkYWxnbyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFNRV8xID09ICJQdWVibGEiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BTUVfMSA9PSAiTW9yZWxvcyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFNRV8xID09ICJHdWVycmVybyIpCgpteGNpdHlfcmVnaW9uX3NocCRjZW50cm9pZCA8LSBteGNpdHlfcmVnaW9uX3NocCAgJT4lIAogIHN0X2NlbnRyb2lkKCkgJT4lIAogIHN0X2dlb21ldHJ5KCkKCnBhZGRpbmdfd2lkdGggPC0gNC41CnBhZGRpbmdfaGVpZ2h0IDwtIDMuNQoKY29sX3BhbCA8LSBjKCIjZmVmMGQ5IiwKICAgICAgICAgICAgICMiI2ZkY2M4YSIsCiAgICAgICAgICAgICAjIiNmYzhkNTkiLAogICAgICAgICAgICAgIyIjZTM0YTMzIiwKICAgICAgICAgICAgICIjYjMwMDAwIikKCiMgMjAyMAptb2JfaW5kaWNhdG9yc18xICU+JSBmaWx0ZXIoTkFNRV8xID09ICJHdWVycmVybyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQU1FXzEgPT0gIkhpZGFsZ28iIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFNRV8xID09ICJNw6l4aWNvIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BTUVfMSA9PSAiUHVlYmxhIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BTUVfMSA9PSAiVGxheGNhbGEiKSAlPiUgCiAgZmlsdGVyKHllYXIgPT0gIjIwMjAiKSAlPiUgCiAgZmlsdGVyKGRpc3RhbmNlX2NsYXNzID09ICI8MTAwIikgJT4lIAogICBnZ3Bsb3QoYWVzKGZpbGwgPSBuZXdfamVua19jbGFzcykpICsKICAgICBnZW9tX3NmKGNvbCA9ICJ3aGl0ZSIsIHNpemUgPSAuMSkgKwogICBjb29yZF9zZigpICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xfcGFsKSArCiAgIyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIk9yUmQiLCAKICAjICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IDEsIAogICMgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMTAtNDIxIiwgIjQyMi0xMjMxIiwgIjEsMjMyLTMsMzcwIiwgIjMsMzcxLTIyLDc2MSIsICI+IDIyLDc2MSIpKSArCiAgIHRoZW1lX21hcCgpICsKICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNjApLAogICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGNvbG91cj0iYmxhY2siKQogICAgICAgICApICsKICAgbGFicyh0aXRsZSA9ICJNZXhpY28gQ2l0eSIpICsKICAgIGdlb21fc2YoZGF0YSA9IG14Y2l0eV9yZWdpb25fc2hwLAogICAgICAgICAgY29sID0gImJsYWNrIiwgCiAgICAgICAgICBzaXplID0gMSwKICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IikgKwogICAgICAgICAgICBjb29yZF9zZih4bGltID0gYyhteGNpdHlfcmVnaW9uX3NocCRjZW50cm9pZFtbMV1dWzFdIC0gcGFkZGluZ193aWR0aCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXhjaXR5X3JlZ2lvbl9zaHAkY2VudHJvaWRbWzFdXVsxXSArIHBhZGRpbmdfd2lkdGggLSAuNSksCiAgICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKG14Y2l0eV9yZWdpb25fc2hwJGNlbnRyb2lkW1sxXV1bMl0gLSBwYWRkaW5nX2hlaWdodCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXhjaXR5X3JlZ2lvbl9zaHAkY2VudHJvaWRbWzFdXVsyXSArIHBhZGRpbmdfaGVpZ2h0KSwKICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBGQUxTRSkKCm14Y2l0eV9tYXAyMDIwIDwtIGxhc3RfcGxvdCgpCmBgYAoKYGBge3J9CiMgMjAyMgoKY29sX3BhbCA8LSBjKCIjZmVmMGQ5IiwKICAgICAgICAgICAgICIjZmRjYzhhIiwKICAgICAgICAgICAgICIjZmM4ZDU5IiwKICAgICAgICAgICAgICIjZTM0YTMzIiwKICAgICAgICAgICAgICIjYjMwMDAwIikKCm1vYl9pbmRpY2F0b3JzXzEgJT4lIGZpbHRlcihOQU1FXzEgPT0gIkd1ZXJyZXJvIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BTUVfMSA9PSAiSGlkYWxnbyIgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQU1FXzEgPT0gIk3DqXhpY28iIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFNRV8xID09ICJQdWVibGEiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFNRV8xID09ICJNb3JlbG9zIiB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BTUVfMSA9PSAiVGxheGNhbGEiKSAlPiUgCiAgZmlsdGVyKHllYXIgPT0gIjIwMjIiKSAlPiUgCiAgZmlsdGVyKGRpc3RhbmNlX2NsYXNzID09ICI8MTAwIikgJT4lIAogICBnZ3Bsb3QoYWVzKGZpbGwgPSBuZXdfamVua19jbGFzcykpICsKICAgICBnZW9tX3NmKGNvbCA9ICJ3aGl0ZSIsIHNpemUgPSAuMSkgKwogICBjb29yZF9zZigpICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xfcGFsKSArCiAgIyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIk9yUmQiLCAKICAjICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IDEsIAogICMgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMTAtNDIxIiwgIjQyMi0xMjMxIiwgIjEsMjMyLTMsMzcwIiwgIjMsMzcxLTIyLDc2MSIsICI+IDIyLDc2MSIpKSArCiAgIHRoZW1lX21hcCgpICsKICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNjApLAogICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGNvbG91cj0iYmxhY2siKQogICAgICAgICApICsKICAgbGFicyh0aXRsZSA9ICJNZXhpY28gQ2l0eSIpICsKICAgIGdlb21fc2YoZGF0YSA9IG14Y2l0eV9yZWdpb25fc2hwLAogICAgICAgICAgY29sID0gImJsYWNrIiwgCiAgICAgICAgICBzaXplID0gMSwKICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IikgKwogICAgICAgICAgICBjb29yZF9zZih4bGltID0gYyhteGNpdHlfcmVnaW9uX3NocCRjZW50cm9pZFtbMV1dWzFdIC0gcGFkZGluZ193aWR0aCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXhjaXR5X3JlZ2lvbl9zaHAkY2VudHJvaWRbWzFdXVsxXSArIHBhZGRpbmdfd2lkdGggLSAuNSksCiAgICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKG14Y2l0eV9yZWdpb25fc2hwJGNlbnRyb2lkW1sxXV1bMl0gLSBwYWRkaW5nX2hlaWdodCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXhjaXR5X3JlZ2lvbl9zaHAkY2VudHJvaWRbWzFdXVsyXSArIHBhZGRpbmdfaGVpZ2h0KSwKICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBGQUxTRSkKbXhjaXR5X21hcDIwMjIgPC0gbGFzdF9wbG90KCkKCmBgYAoKYGBge3J9CnBuZygiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9vdXRwdXRzL2Nsb3JvcGxldGgtbWFwcy9tZXhpY28vY2xvcm9wbGV0aC1teGNpdHkyMDIwLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBteGNpdHlfbWFwMjAyMApkZXYub2ZmKCkKCnBuZygiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9vdXRwdXRzL2Nsb3JvcGxldGgtbWFwcy9tZXhpY28vY2xvcm9wbGV0aC1teGNpdHkyMDIyLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBteGNpdHlfbWFwMjAyMgpkZXYub2ZmKCkKYGBgCgojIyMgQ3JlYXRlIGJhciBwbG90CgojIyMjIFNob3J0LWRpc3RhbmNlCgpgYGB7cn0KIyAyMDIwCmNvbF9wYWwgPC0gYygiI2ZlZjBkOSIsCiAgICAgICAgICAgICAjIiNmZGNjOGEiLAogICAgICAgICAgICAgIyIjZmM4ZDU5IiwKICAgICAgICAgICAgICMiI2UzNGEzMyIsCiAgICAgICAgICAgICAiI2IzMDAwMCIpCgptb2JfaW5kaWNhdG9yc18xICU+JSBmaWx0ZXIoeWVhciA9PSAiMjAyMCIpICU+JQogIGZpbHRlcihkaXN0YW5jZV9jbGFzcyA9PSAiPDEwMCIpICU+JSAKICBhcnJhbmdlKGRlc2Moc3VtX291dGZsb3cpKSAlPiUgCiAgICBtdXRhdGUob3V0Zmxvd190b3RhbCA9IHN1bShzdW1fb3V0ZmxvdyksCiAgICAgICAgIG91dGZsb3dfcGVyY2VudCA9IHJvdW5kKCAoc3VtX291dGZsb3cvb3V0Zmxvd190b3RhbCkqMTAwLCAyICkgKSAlPiUgCiAgaGVhZChuID0gMTApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKE5BTUVfMiwgb3V0Zmxvd19wZXJjZW50KSwgeSA9IG91dGZsb3dfcGVyY2VudCwgZmlsbCA9IG5ld19qZW5rX2NsYXNzKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIgKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sX3BhbCkgKwogIHRoZW1lX3R1ZnRlMigpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiVG9wIHRlbiBvdXRmbG93cyIsCiAgICAgICB5ID0gIlBlcmNlbnQgKCUpIikgKwogIHRoZW1lKHBsb3QubWFyZ2luPW1hcmdpbigxLDAsMSwxLCJjbSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzNSksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIyBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpKSAjIFNldCBjdXN0b20geS1heGlzIGxhYmVscwoKYmFycF9zaG9ydDIwMjAgPC0gbGFzdF9wbG90KCkKYGBgCgpgYGB7cn0KIyAyMDIyCgogY29sX3BhbCA8LSBjKCMiI2ZlZjBkOSIsCiMgICAgICAgICAgICAgICIjZmRjYzhhIiwKIyAgICAgICAgICAgICAgIiNmYzhkNTkiLAojICAgICAgICAgICAgICAiI2UzNGEzMyIsCiAgICAgICAgICAgICAiI2IzMDAwMCIpCgptb2JfaW5kaWNhdG9yc18xICU+JSBmaWx0ZXIoeWVhciA9PSAiMjAyMiIpICU+JQogIGZpbHRlcihkaXN0YW5jZV9jbGFzcyA9PSAiPDEwMCIpICU+JSAKICBhcnJhbmdlKGRlc2Moc3VtX291dGZsb3cpKSAlPiUgCiAgICBtdXRhdGUob3V0Zmxvd190b3RhbCA9IHN1bShzdW1fb3V0ZmxvdyksCiAgICAgICAgIG91dGZsb3dfcGVyY2VudCA9IHJvdW5kKCAoc3VtX291dGZsb3cvb3V0Zmxvd190b3RhbCkqMTAwLCAyICkgKSAlPiUgCiAgZGlzdGluY3QoTkFNRV8yLCAua2VlcF9hbGw9VFJVRSkgJT4lIAogIGhlYWQobiA9IDEwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihOQU1FXzIsIG91dGZsb3dfcGVyY2VudCksIHkgPSBvdXRmbG93X3BlcmNlbnQsIGZpbGwgPSBuZXdfamVua19jbGFzcykpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiICkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGNvbF9wYWwpICsKICB0aGVtZV90dWZ0ZTIoKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlRvcCB0ZW4gb3V0Zmxvd3MiLAogICAgICAgeSA9ICJQZXJjZW50ICglKSIpICsKICB0aGVtZShwbG90Lm1hcmdpbj1tYXJnaW4oMSwwLDEsMSwiY20iKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzUpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAjYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgIyBTZXQgY3VzdG9tIHktYXhpcyBsYWJlbHMKCmJhcnBfc2hvcnQyMDIyIDwtIGxhc3RfcGxvdCgpCmBgYAoKYGBge3J9CnBuZygiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9vdXRwdXRzL2Nsb3JvcGxldGgtbWFwcy9tZXhpY28vYmFycF9zaG9ydDIwMjAucG5nIiwgdW5pdHM9ImluIiwgd2lkdGg9OCwgaGVpZ2h0PTEwLCByZXM9MzAwKQogIGJhcnBfc2hvcnQyMDIwCmRldi5vZmYoKQoKcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL21leGljby9iYXJwX3Nob3J0MjAyMi5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHJlcz0zMDApCiAgYmFycF9zaG9ydDIwMjIKZGV2Lm9mZigpCmBgYAoKCiMjIyMgTG9uZy1kaXN0YW5jZQoKYGBge3J9CiMgMjAyMApjb2xfcGFsIDwtIGMoIyIjZmVmMGQ5IiwKICAgICAgICAgICAgICMiI2ZkY2M4YSIsCiAgICAgICAgICAgICAjIiNmYzhkNTkiLAogICAgICAgICAgICAgIiNlMzRhMzMiLAogICAgICAgICAgICAgIiNiMzAwMDAiKQoKbW9iX2luZGljYXRvcnNfMSAlPiUgZmlsdGVyKHllYXIgPT0gIjIwMjAiKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2VfY2xhc3MgPT0gIj4xMDAiKSAlPiUgCiAgYXJyYW5nZShkZXNjKHN1bV9vdXRmbG93KSkgJT4lIAogICAgbXV0YXRlKG91dGZsb3dfdG90YWwgPSBzdW0oc3VtX291dGZsb3cpLAogICAgICAgICBvdXRmbG93X3BlcmNlbnQgPSByb3VuZCggKHN1bV9vdXRmbG93L291dGZsb3dfdG90YWwpKjEwMCwgMiApICkgJT4lIAogIGhlYWQobiA9IDEwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihOQU1FXzIsIG91dGZsb3dfcGVyY2VudCksIHkgPSBvdXRmbG93X3BlcmNlbnQsIGZpbGwgPSBuZXdfamVua19jbGFzcykpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiICkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGNvbF9wYWwpICsKICB0aGVtZV90dWZ0ZTIoKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlRvcCB0ZW4gb3V0Zmxvd3MiLAogICAgICAgeSA9ICJQZXJjZW50ICglKSIpICsKICB0aGVtZShwbG90Lm1hcmdpbj1tYXJnaW4oMSwwLDEsMSwiY20iKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzUpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICMgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgIyBTZXQgY3VzdG9tIHktYXhpcyBsYWJlbHMKCmJhcnBfbG9uZzIwMjAgPC0gbGFzdF9wbG90KCkKYGBgCmBgYHtyfQojIDIwMjIKY29sX3BhbCA8LSBjKCMiI2ZlZjBkOSIsCiAgICAgICAgICAgICAjIiNmZGNjOGEiLAogICAgICAgICAgICAgIyIjZmM4ZDU5IiwKICAgICAgICAgICAgICMiI2UzNGEzMyIsCiAgICAgICAgICAgICAiI2IzMDAwMCIpCgptb2JfaW5kaWNhdG9yc18xICU+JSBmaWx0ZXIoeWVhciA9PSAiMjAyMiIpICU+JQogIGZpbHRlcihkaXN0YW5jZV9jbGFzcyA9PSAiPjEwMCIpICU+JSAKICBhcnJhbmdlKGRlc2Moc3VtX291dGZsb3cpKSAlPiUgCiAgICBtdXRhdGUob3V0Zmxvd190b3RhbCA9IHN1bShzdW1fb3V0ZmxvdyksCiAgICAgICAgIG91dGZsb3dfcGVyY2VudCA9IHJvdW5kKCAoc3VtX291dGZsb3cvb3V0Zmxvd190b3RhbCkqMTAwLCAyICkgKSAlPiUgCiAgaGVhZChuID0gMTApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKE5BTUVfMiwgb3V0Zmxvd19wZXJjZW50KSwgeSA9IG91dGZsb3dfcGVyY2VudCwgZmlsbCA9IG5ld19qZW5rX2NsYXNzKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIgKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sX3BhbCkgKwogIHRoZW1lX3R1ZnRlMigpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiVG9wIHRlbiBvdXRmbG93cyIsCiAgICAgICB5ID0gIlBlcmNlbnQgKCUpIikgKwogIHRoZW1lKHBsb3QubWFyZ2luPW1hcmdpbigxLDAsMSwxLCJjbSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzNSksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIyBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpKSAjIFNldCBjdXN0b20geS1heGlzIGxhYmVscwoKYmFycF9sb25nMjAyMiA8LSBsYXN0X3Bsb3QoKQpgYGAKCgpgYGB7cn0KcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL21leGljby9iYXJwX2xvbmcyMDIwLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBiYXJwX2xvbmcyMDIwCmRldi5vZmYoKQoKcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL21leGljby9iYXJwX2xvbmcyMDIyLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBiYXJwX2xvbmcyMDIyCmRldi5vZmYoKQpgYGAKCiMjIyBTYXZpbmcgY29tYmluZWQgbWFwcwpgYGB7cn0KcG5nKCIvVXNlcnMvZnJhbmNpc2Nvcm93ZS9Ecm9wYm94L0ZyYW5jaXNjby9SZXNlYXJjaC9pbl9wcm9ncmVzcy9yZWNhc3QvY2VwYWwtcmVwb3J0L291dHB1dHMvY2xvcm9wbGV0aC1tYXBzL2Nsb3JvcGxldGgtbWFwLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcmVzPTMwMCkKICBvdXRmbG93X3Bsb3RfYXJnICsgb3V0Zmxvd19wbG90X2NoaSArIG91dGZsb3dfcGxvdF9tZXgKZGV2Lm9mZigpCmBgYAoKYGBge3J9CnBuZygiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9vdXRwdXRzL2Nsb3JvcGxldGgtbWFwcy9jbG9yb3BsZXRoLW1hcDEucG5nIiwgdW5pdHM9ImluIiwgd2lkdGg9OCwgaGVpZ2h0PTEwLCByZXM9MzAwKQogIHdyYXBfcGxvdHMob3V0Zmxvd19wbG90X2FyZywKICAgICAgICAgICAgIG91dGZsb3dfcGxvdF9jaGksCiAgICAgICAgICAgICBvdXRmbG93X3Bsb3RfbWV4KQpkZXYub2ZmKCkKYGBgCgoKYGBge3J9CnBuZygiL1VzZXJzL2ZyYW5jaXNjb3Jvd2UvRHJvcGJveC9GcmFuY2lzY28vUmVzZWFyY2gvaW5fcHJvZ3Jlc3MvcmVjYXN0L2NlcGFsLXJlcG9ydC9vdXRwdXRzL2Nsb3JvcGxldGgtbWFwcy9jbG9yb3BsZXRoLW1hcDIucG5nIiwgdW5pdHM9ImluIiwgd2lkdGg9OCwgaGVpZ2h0PTEwLCByZXM9MzAwKQogIHBsb3RfZ3JpZChvdXRmbG93X3Bsb3RfYXJnLCBvdXRmbG93X3Bsb3RfY2hpLCBvdXRmbG93X3Bsb3RfbWV4LCBuY29sPTMsIGFsaWduPSJoIikKZGV2Lm9mZigpCmBgYAoKCgoKCg==